JavaScript로 전역 고유 식별자를 만들려고합니다. 모든 브라우저에서 어떤 루틴을 사용할 수 있는지, 내장 난수 생성기가 어떻게 "랜덤"되고 시드되었는지 잘 모르겠습니다.
GUID / UUID는 32 자 이상이어야하며 ASCII 범위를 유지하여 전달할 때 문제가 발생하지 않도록해야합니다.
JavaScript로 전역 고유 식별자를 만들려고합니다. 모든 브라우저에서 어떤 루틴을 사용할 수 있는지, 내장 난수 생성기가 어떻게 "랜덤"되고 시드되었는지 잘 모르겠습니다.
GUID / UUID는 32 자 이상이어야하며 ASCII 범위를 유지하여 전달할 때 문제가 발생하지 않도록해야합니다.
답변:
RFC 4122 에 따르면 GUID (Globally Unique IDentifier)라고도하는 UUID (Universally Unique IDentifier) 는 특정 고유성을 보장하도록 설계된 식별자입니다.
몇 줄의 JS에서 RFC 호환 UUID를 구현할 수 있지만 (예 : @broofa의 답변 참조) 몇 가지 일반적인 함정이 있습니다.
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
" 형식이어야합니다 . 여기서 x는 [0-9, af] 중 하나임) 중 하나이고 M 은 [1-5] 중 하나이고 N 은 [8, 9, a 또는 b] 임 )Math.random
)따라서 프로덕션 환경을위한 코드를 작성하는 개발자는 uuid 모듈 과 같이 엄격하고 잘 관리 된 구현을 사용하는 것이 좋습니다 .
을 위해 RFC4122의 버전 4 준수 솔루션이 한 줄 (틱) 솔루션은 내가 가지고 올 수있는 가장 컴팩트 :
function uuidv4() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
}
console.log(uuidv4());
2015-06-02 업데이트 : UUID 고유성은 기본 난수 생성기 (RNG)에 크게 의존합니다. 위의 솔루션 Math.random()
은 간결성을 위해 사용 되지만 고품질 RNG Math.random()
는 아닙니다 . 자세한 내용은 Adam Hyland의 Math.random ()에 대한 훌륭한 글 을 참조하십시오. 보다 강력한 솔루션을 위해서는 uuid 모듈 사용을 고려하십시오 위해서는 고품질 RNG API를 사용 .
업데이트, 2015년 8월 26일는 : 사이드 참고로,이 요점은 충돌의 특정 확률에 도달하기 전에 생성 할 수 있습니다 얼마나 많은 ID를 확인하는 방법에 대해 설명합니다. 예를 들어 3.26x10 15 버전 4 RFC4122 UUID를 사용하면 1 백만 분의 1의 충돌 가능성이 있습니다.
2017-06-28 업데이트 : Chrome 개발자 가 Chrome, Firefox 및 Safari의 Math.random PRNG 품질 상태를 논의한 좋은 기사입니다 . tl; dr-2015 년 말 기준으로 "아주 훌륭"하지만 암호화 품질은 아닙니다. 이 문제를 해결하기 위해 ES6, crypto
API 및 약간의 JS 마법사 를 사용하는 위 솔루션의 업데이트 된 버전은 다음 과 같습니다.
function uuidv4() {
return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
(c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
);
}
console.log(uuidv4());
c== 'x'
대신에 c === 'x'
. jshint가 실패했기 때문입니다.
나는 Broofa의 대답 이 얼마나 깨끗한 지 정말 좋아 하지만 불행히도 구현Math.random
이 잘못 되면 충돌의 가능성이 있습니다.
다음 은 타임 스탬프의 16 진 부분으로 처음 13 개의 16 진수를 오프셋하고 페이지로드 이후 마이크로 초의 16 진 부분으로 오프셋을 고갈 시켜서이 문제를 해결 하는 유사한 RFC4122 버전 4 호환 솔루션입니다. 이렇게 Math.random
하면 동일한 시드에 있더라도 두 클라이언트 모두 페이지로드 이후 (고성능 시간이 지원되는 경우) 이후 정확히 동일한 밀리 초 (또는 10,000 년 이상) 후 UUID를 정확히 동일한 수의 마이크로 초로 생성해야합니다. 동일한 UUID를 얻으십시오.
function generateUUID() { // Public Domain/MIT
var d = new Date().getTime();//Timestamp
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16;//random number between 0 and 16
if(d > 0){//Use timestamp until depleted
r = (d + r)%16 | 0;
d = Math.floor(d/16);
} else {//Use microseconds since page-load if supported
r = (d2 + r)%16 | 0;
d2 = Math.floor(d2/16);
}
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
console.log(generateUUID())
new Date().getTime()
매 밀리 초마다 업데이트되지는 않습니다. 이것이 알고리즘의 예상 무작위성에 어떤 영향을 미치는지 잘 모르겠습니다.
d = Math.floor(d/16);
있습니까?
broofa의 대답은 실제로 매끄럽고 매끄 럽습니다 .rfc4122 호환, 다소 읽기 쉽고 컴팩트합니다. 대박!
그러나 그 정규 표현식, 많은 replace()
콜백, toString()
및 Math.random()
함수 호출 (그가 4 비트의 결과 만 사용하고 나머지는 낭비하는 곳)을 보고 있다면 성능에 대해 궁금해 할 수 있습니다. 실제로 joelpt는로 일반 GUID 속도를 위해 RFC를 포기하기로 결정했습니다 generateQuickGUID
.
그러나 속도 와 RFC 준수를 얻을 수 있습니까? 나는 찬성! 가독성을 유지할 수 있습니까? 글쎄 ... 실제로는 아니지만 따라 가면 쉽다.
그러나 먼저, 내 결과는 broofa guid
(허용 된 답변) 및 비 rfc 호환과 비교되었습니다 generateQuickGuid
.
Desktop Android
broofa: 1617ms 12869ms
e1: 636ms 5778ms
e2: 606ms 4754ms
e3: 364ms 3003ms
e4: 329ms 2015ms
e5: 147ms 1156ms
e6: 146ms 1035ms
e7: 105ms 726ms
guid: 962ms 10762ms
generateQuickGuid: 292ms 2961ms
- Note: 500k iterations, results will vary by browser/cpu.
따라서 6 번의 최적화 반복으로 12X 이상으로 가장 인기있는 답변 , 9X 이상으로 허용되는 답변 및 2-3X로 빠른 비준수 답변을 이겼습니다. . 그리고 나는 여전히 rfc4122를 준수합니다.
방법에 관심이 있습니까? http://jsfiddle.net/jcward/7hyaC/3/ 및 http://jsperf.com/uuid-generator-opt/4 에 전체 소스를 넣었습니다.
설명을 위해, broofa의 코드로 시작해 봅시다 :
function broofa() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
}
console.log(broofa())
따라서 x
임의의 16 진수로, y
임의의 데이터 ( 10
RFC 사양 에 따라 상위 2 비트를 강제로 제외)를 대체 하며 정규 표현식은 문자 -
또는 4
문자 와 일치 하지 않으므로 처리 할 필요가 없습니다. 매우 매끄 럽습니다.
가장 먼저 알아야 할 것은 정규 표현식과 마찬가지로 함수 호출이 비싸다는 것입니다 (1을 사용하지만 각 일치에 대해 하나씩 32 개의 콜백이 있으며 각 32 개의 콜백에서 Math.random () 및 v를 호출합니다. toString (16)).
성능을 향한 첫 단계는 RegEx와 콜백 함수를 제거하고 대신 간단한 루프를 사용하는 것입니다. 이것은 broofa가 아닌 반면에 -
and 를 처리해야 함을 의미 4
합니다. 또한 String Array 인덱싱을 사용하여 매끄러운 String 템플릿 아키텍처를 유지할 수 있습니다.
function e1() {
var u='',i=0;
while(i++<36) {
var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);
u+=(c=='-'||c=='4')?c:v.toString(16)
}
return u;
}
console.log(e1())
기본적으로, 동일한 내부 로직, 우리는 제외시켰다 확인 -
하거나 4
, 잠시 루프를 사용하여 (대신replace()
콜백 것은) 우리에게 거의 3 배 개선을 얻는다!
다음 단계는 데스크톱에서는 작은 단계이지만 모바일에서는 상당한 차이가 있습니다. 더 적은 Math.random () 호출을 만들고 각 반복마다 시프트되는 임의 버퍼로 87 %를 버리지 않고 모든 임의의 비트를 활용합시다. 다음과 같은 경우를 대비하여 해당 템플리트 정의를 루프 밖으로 이동 시키십시오.
function e2() {
var u='',m='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',i=0,rb=Math.random()*0xffffffff|0;
while(i++<36) {
var c=m[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
u+=(c=='-'||c=='4')?c:v.toString(16);rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
}
return u
}
console.log(e2())
이는 플랫폼에 따라 10-30 %를 절약합니다. 나쁘지 않다. 그러나 다음 큰 단계는 최적화 클래식 인 조회 테이블과 함께 toString 함수 호출을 완전히 제거합니다. 간단한 16 요소 룩업 테이블은 훨씬 짧은 시간에 toString (16) 작업을 수행합니다.
function e3() {
var h='0123456789abcdef';
var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
/* same as e4() below */
}
function e4() {
var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
var k=['x','x','x','x','x','x','x','x','-','x','x','x','x','-','4','x','x','x','-','y','x','x','x','-','x','x','x','x','x','x','x','x','x','x','x','x'];
var u='',i=0,rb=Math.random()*0xffffffff|0;
while(i++<36) {
var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
}
return u
}
console.log(e4())
다음 최적화는 또 다른 고전입니다. 각 루프 반복에서 4 비트의 출력 만 처리하므로 루프 수를 반으로 줄이고 각 반복마다 8 비트를 처리하겠습니다. 여전히 RFC 호환 비트 위치를 처리해야하기 때문에 까다로울 수 있지만 그렇게 어렵지는 않습니다. 그런 다음 0x00-0xff를 저장하기 위해 더 큰 조회 테이블 (16x16 또는 256)을 만들어야하며 e5 () 함수 외부에서 한 번만 작성합니다.
var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e5() {
var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];
var u='',i=0,rb=Math.random()*0xffffffff|0;
while(i++<20) {
var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));
u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8
}
return u
}
console.log(e5())
나는 여전히 256 요소 LUT를 사용하여 한 번에 16 비트를 처리하는 e6 ()을 시도했으며 최적화의 감소 수익을 보여주었습니다. 반복 횟수는 적었지만 내부 로직은 처리 증가로 인해 복잡해졌으며 데스크톱에서도 동일하게 수행되었으며 모바일에서는 ~ 10 % 더 빨랐습니다.
적용 할 최종 최적화 기술-루프를 전개하십시오. 우리는 고정 된 횟수로 반복하기 때문에 기술적으로 이것을 모두 손으로 작성할 수 있습니다. 나는 다시 할당하고 성능을 향상시키는 단일 무작위 변수 r로 이것을 한 번 시도했다. 그러나 4 개의 변수에 임의의 데이터를 미리 할당 한 다음 조회 테이블을 사용하고 적절한 RFC 비트를 적용하면이 버전이 모두 담배를 피 웁니다.
var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e7()
{
var d0 = Math.random()*0xffffffff|0;
var d1 = Math.random()*0xffffffff|0;
var d2 = Math.random()*0xffffffff|0;
var d3 = Math.random()*0xffffffff|0;
return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
}
console.log(e7())
Modualized : http://jcward.com/UUID.js -UUID.generate()
재미있는 점은 16 바이트의 임의 데이터를 생성하는 것이 쉽다는 것입니다. 전체 트릭은 RFC 준수를 사용하여 문자열 형식으로 표현하며 16 바이트의 임의 데이터, 롤링되지 않은 루프 및 조회 테이블을 사용하여 가장 엄격하게 수행됩니다.
나는 나의 논리가 정확하기를 희망한다. 이런 종류의 지루한 비트 작업에서 실수를 저지르는 것은 매우 쉽다. 그러나 출력은 나에게 좋아 보인다. 코드 최적화를 통해이 미친 듯이 즐거운 시간을 보내시기 바랍니다.
조언 : 나의 주요 목표는 잠재적 인 최적화 전략을 보여주고 가르치는 것이 었습니다. 다른 답변은 충돌 및 진정한 난수와 같은 중요한 주제를 다루며, 이는 좋은 UUID를 생성하는 데 중요합니다.
Math.random()*0xFFFFFFFF
행은 Math.random()*0x100000000
완전한 임의성을 >>>0
가져야하며 |0
값을 부호가없는 상태로 유지하는 대신 사용해야합니다 (현재 코드는 서명되어 있어도 괜찮습니다). 마지막으로 요즘에는 사용 window.crypto.getRandomValues
가능한 경우 사용 하는 것이 좋으며 반드시 필요한 경우에만 Math.random으로 대체하는 것이 좋습니다. Math.random은 128 비트 미만의 엔트로피를 가질 수 있으며,이 경우 필요한 것보다 충돌에 더 취약합니다.
다음은 RFC 4122 , 섹션 4.4 (정확히 임의 또는 의사 난수에서 UUID를 작성하기위한 알고리즘)를 기반으로하는 일부 코드 입니다.
function createUUID() {
// http://www.ietf.org/rfc/rfc4122.txt
var s = [];
var hexDigits = "0123456789abcdef";
for (var i = 0; i < 36; i++) {
s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
}
s[14] = "4"; // bits 12-15 of the time_hi_and_version field to 0010
s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1); // bits 6-7 of the clock_seq_hi_and_reserved to 01
s[8] = s[13] = s[18] = s[23] = "-";
var uuid = s.join("");
return uuid;
}
var s = new Array(36);
let uniqueId = Math.random().toString(36).substring(2) + Date.now().toString(36);
ID가 1 밀리 초 이상 생성되면 100 % 고유합니다.
짧은 간격으로 두 개의 ID가 생성되고 임의 방법이 실제로 무작위라고 가정하면 전 세계적으로 고유 할 가능성이있는 99.99999999999999 % 인 ID를 생성합니다 (10 ^ 15 중 1의 충돌).
더 많은 자릿수를 추가하여이 수를 늘릴 수 있지만 100 % 고유 ID를 생성하려면 글로벌 카운터를 사용해야합니다.
RFC 호환성이 필요한 경우이 형식은 유효한 버전 4 GUID로 전달됩니다.
let u = Date.now().toString(16) + Math.random().toString(16) + '0'.repeat(16);
let guid = [u.substr(0,8), u.substr(8,4), '4000-8' + u.substr(13,3), u.substr(16,12)].join('-');
편집 : 위의 코드는 의도를 따르지 만 RFC의 글자는 아닙니다. 다른 불일치 중에는 임의의 숫자가 짧습니다. (필요한 경우 임의의 숫자를 더 추가하십시오.) 거꾸로하면 이것이 정말 빠릅니다. GUID의 유효성을 테스트 할 수 있습니다.
[slug, date, random].join("_")
를 생성하기 위해)를 사용 usr_1dcn27itd_hj6onj6phr
합니다.이를 통해 id가 "만들기"필드로도 두 배가됩니다
형식에서 문자열 생성기 방식과 같은 가장 빠른 GUID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
. 표준 호환 GUID는 생성하지 않습니다.
이 구현의 천만 번의 실행은 32.5 초 밖에 걸리지 않습니다. 이는 브라우저에서 가장 빠른 속도입니다 (루프 / 반복없는 유일한 솔루션).
이 기능은 다음과 같이 간단합니다.
/**
* Generates a GUID string.
* @returns {string} The generated GUID.
* @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
* @author Slavik Meltser.
* @link http://slavik.meltser.info/?p=142
*/
function guid() {
function _p8(s) {
var p = (Math.random().toString(16)+"000000000").substr(2,8);
return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
}
return _p8() + _p8(true) + _p8(true) + _p8();
}
성능을 테스트하기 위해 다음 코드를 실행할 수 있습니다.
console.time('t');
for (var i = 0; i < 10000000; i++) {
guid();
};
console.timeEnd('t');
나는 당신의 대부분이 내가 한 일을 이해할 것이라고 확신하지만, 설명이 필요한 사람이 적어도 한 명있을 것입니다.
알고리즘 :
Math.random()
함수는 소수점 이하 자릿수 (예 :) 뒤에 16 자리의 0과 1 사이의 10 진수를 반환합니다 0.4363923368509859
.0.6fb7687f
). Math.random().toString(16)
.0.
접두사 ( 0.6fb7687f
=>
6fb7687f
)를 잘라 내고 8 개의 16 진 문자로 된 문자열을 얻습니다. (Math.random().toString(16).substr(2,8)
.Math.random()
함수는 0.4363
끝에서 0으로 인해 더 짧은 숫자 (예 :)를 반환 합니다 (위의 예에서 실제로 숫자는 0.4363000000000000
). 그렇기 때문에이 문자열 "000000000"
(0이 0 인 문자열)에 추가 한 다음 substr()
9 개의 문자를 정확하게 만드는 기능으로 잘라냅니다 (오른쪽에 0을 채 웁니다).Math.random()
함수가 정확히 0 또는 1을 반환 할 때 (각각에 대해 1 / 10 ^ 16의 확률) 더 나쁜 경우 시나리오 때문입니다 . 그렇기 때문에 9 개의 0을 추가 ( "0"+"000000000"
또는 "1"+"000000000"
) 한 다음 길이가 8자인 두 번째 색인 (3 번째 문자)에서 잘라 내야했습니다. 나머지 경우에는 0을 추가해도 결과가 잘 리므로 결과에 영향을 미치지 않습니다. Math.random().toString(16)+"000000000").substr(2,8)
.어셈블리 :
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
.XXXXXXXX
및 -XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
.이 s
매개 변수는 함수에 대시를 추가할지 여부를 알려줍니다._p8() + _p8(true) + _p8(true) + _p8()
하고 반환합니다.즐겨! :-)
다음은 Chrome의 충돌에 대한 해결 방법과 함께 가장 많이 투표 된 답변 의 조합입니다 .
generateGUID = (typeof(window.crypto) != 'undefined' &&
typeof(window.crypto.getRandomValues) != 'undefined') ?
function() {
// If we have a cryptographically secure PRNG, use that
// /programming/6906916/collisions-when-generating-uuids-in-javascript
var buf = new Uint16Array(8);
window.crypto.getRandomValues(buf);
var S4 = function(num) {
var ret = num.toString(16);
while(ret.length < 4){
ret = "0"+ret;
}
return ret;
};
return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
}
:
function() {
// Otherwise, just use Math.random
// /programming/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
};
테스트하려는 경우 jsbin에서 .
, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` 버전은 xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
.
다음은 ASCII 안전 GUID와 같은 고유 식별자를 생성하기위한 완전히 호환되지 않지만 성능이 뛰어난 구현입니다.
function generateQuickGuid() {
return Math.random().toString(36).substring(2, 15) +
Math.random().toString(36).substring(2, 15);
}
RFC 호환 GUID보다 짧고 고유 한 UID를 생성하는 26 개의 [a-z0-9] 문자를 생성합니다. 사람의 가독성이 중요한 경우 대시를 사소하게 추가 할 수 있습니다.
다음은이 함수의 사용법 예제와 타이밍 및이 질문의 다른 답변 중 일부입니다. 타이밍은 Chrome m25에서 각각 천만 번 반복하여 수행되었습니다.
>>> generateQuickGuid()
"nvcjf1hs7tf8yyk4lmlijqkuo9"
"yq6gipxqta4kui8z05tgh9qeel"
"36dh5sec7zdj90sk2rx7pjswi2"
runtime: 32.5s
>>> GUID() // John Millikin
"7a342ca2-e79f-528e-6302-8f901b0b6888"
runtime: 57.8s
>>> regexGuid() // broofa
"396e0c46-09e4-4b19-97db-bd423774a4b3"
runtime: 91.2s
>>> createUUID() // Kevin Hakanson
"403aa1ab-9f70-44ec-bc08-5d5ac56bd8a5"
runtime: 65.9s
>>> UUIDv4() // Jed Schmidt
"f4d7d31f-fa83-431a-b30c-3e6cc37cc6ee"
runtime: 282.4s
>>> Math.uuid() // broofa
"5BD52F55-E68F-40FC-93C2-90EE069CE545"
runtime: 225.8s
>>> Math.uuidFast() // broofa
"6CB97A68-23A2-473E-B75B-11263781BBE6"
runtime: 92.0s
>>> Math.uuidCompact() // broofa
"3d7b7a06-0a67-4b67-825c-e5c43ff8c1e8"
runtime: 229.0s
>>> bitwiseGUID() // jablko
"baeaa2f-7587-4ff1-af23-eeab3e92"
runtime: 79.6s
>>>> betterWayGUID() // Andrea Turri
"383585b0-9753-498d-99c3-416582e9662c"
runtime: 60.0s
>>>> UUID() // John Fowler
"855f997b-4369-4cdb-b7c9-7142ceaf39e8"
runtime: 62.2s
타이밍 코드는 다음과 같습니다.
var r;
console.time('t');
for (var i = 0; i < 10000000; i++) {
r = FuncToTest();
};
console.timeEnd('t');
다음 은 https://gist.github.com/982883의 사용자 jed 가 작성한 주석의 2011 년 10 월 9 일자 솔루션입니다 .
UUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}
이것은 현재 최고 등급의 답변 과 동일한 목표를 달성 하지만, 강제, 재귀 및 지수 표기법을 활용하여 바이트 수가 50 바이트 이상 줄어 듭니다. 어떻게 작동하는지 궁금한 사람들을 위해 이전 버전의 함수에 주석이 달린 형식이 있습니다.
UUIDv4 =
function b(
a // placeholder
){
return a // if the placeholder was passed, return
? ( // a random number from 0 to 15
a ^ // unless b is 8,
Math.random() // in which case
* 16 // a random number from
>> a/4 // 8 to 11
).toString(16) // in hexadecimal
: ( // or otherwise a concatenated string:
[1e7] + // 10000000 +
-1e3 + // -1000 +
-4e3 + // -4000 +
-8e3 + // -80000000 +
-1e11 // -100000000000,
).replace( // replacing
/[018]/g, // zeroes, ones, and eights with
b // random hex digits
)
}
function generateGuid() {
var result, i, j;
result = '';
for(j=0; j<32; j++) {
if( j == 8 || j == 12 || j == 16 || j == 20)
result = result + '-';
i = Math.floor(Math.random()*16).toString(16).toUpperCase();
result = result + i;
}
return result;
}
ActiveX 컨트롤을 사용하는 다른 방법이 있지만 이러한 방법을 피하십시오!
편집 : GUID 생성기가 고유 키를 보장 할 수 없다는 것을 지적 할 가치가 있다고 생각했습니다 ( wikipedia 기사 확인) ). 충돌 가능성이 항상 있습니다. GUID는 단순히 충돌의 변화를 거의 없앨 수 있도록 충분히 큰 키 공간을 제공합니다.
node-uuid ( https://github.com/kelektiv/node-uuid )를
간단하고 빠른 생성 RFC4122 UUIDS
풍모:
NPM을 사용하여 설치 :
npm install uuid
또는 브라우저를 통한 UUID 사용
원시 파일 다운로드 (uuid v1) : https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js 원시 파일 다운로드 (uuid v4) : https://raw.githubusercontent.com/kelektiv/node -uuid / master / v4.js
더 작은 것을 원하십니까? 이것을 확인하십시오 : https://gist.github.com/jed/982883
용법:
// Generate a v1 UUID (time-based)
const uuidV1 = require('uuid/v1');
uuidV1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'
// Generate a v4 UUID (random)
const uuidV4 = require('uuid/v4');
uuidV4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'
// Generate a v5 UUID (namespace)
const uuidV5 = require('uuid/v5');
// ... using predefined DNS namespace (for domain names)
uuidV5('hello.example.com', v5.DNS)); // -> 'fdda765f-fc57-5604-a269-52a7df8164ec'
// ... using predefined URL namespace (for, well, URLs)
uuidV5('http://example.com/hello', v5.URL); // -> '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'
// ... using a custom namespace
const MY_NAMESPACE = '(previously generated unique uuid string)';
uuidV5('hello', MY_NAMESPACE); // -> '90123e1c-7512-523e-bb28-76fab9f2f73d'
ES6 :
import uuid from 'uuid/v4';
const id = uuid();
var uuid = function() {
var buf = new Uint32Array(4);
window.crypto.getRandomValues(buf);
var idx = -1;
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
idx++;
var r = (buf[idx>>3] >> ((idx%8)*4))&15;
var v = c == 'x' ? r : (r&0x3|0x8);
return v.toString(16);
});
};
편집하다:
이 기능을 사용하고있는 프로젝트를 다시 방문하여 자세한 정보를 싫어했습니다. 그러나 적절한 무작위성이 필요했습니다.
버퍼에서 니블 크기의 창을 추출하는 Briguy37의 답변과 일부 비트 연산자를 기반으로 한 버전입니다.
Java UUID로 비 규격 UUID를 구문 분석하는 데 문제가 있었으므로 RFC 유형 4 (임의) 스키마를 준수해야합니다.
이 글타래에서 최고의 답변을 조합 한 간단한 자바 스크립트 모듈.
var crypto = window.crypto || window.msCrypto || null; // IE11 fix
var Guid = Guid || (function() {
var EMPTY = '00000000-0000-0000-0000-000000000000';
var _padLeft = function(paddingString, width, replacementChar) {
return paddingString.length >= width ? paddingString : _padLeft(replacementChar + paddingString, width, replacementChar || ' ');
};
var _s4 = function(number) {
var hexadecimalResult = number.toString(16);
return _padLeft(hexadecimalResult, 4, '0');
};
var _cryptoGuid = function() {
var buffer = new window.Uint16Array(8);
window.crypto.getRandomValues(buffer);
return [_s4(buffer[0]) + _s4(buffer[1]), _s4(buffer[2]), _s4(buffer[3]), _s4(buffer[4]), _s4(buffer[5]) + _s4(buffer[6]) + _s4(buffer[7])].join('-');
};
var _guid = function() {
var currentDateMilliseconds = new Date().getTime();
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(currentChar) {
var randomChar = (currentDateMilliseconds + Math.random() * 16) % 16 | 0;
currentDateMilliseconds = Math.floor(currentDateMilliseconds / 16);
return (currentChar === 'x' ? randomChar : (randomChar & 0x7 | 0x8)).toString(16);
});
};
var create = function() {
var hasCrypto = crypto != 'undefined' && crypto !== null,
hasRandomValues = typeof(window.crypto.getRandomValues) != 'undefined';
return (hasCrypto && hasRandomValues) ? _cryptoGuid() : _guid();
};
return {
newGuid: create,
empty: EMPTY
};
})();
// DEMO: Create and show GUID
console.log(Guid.newGuid());
용법:
Guid.newGuid ()
"c6c2d12f-d76b-5739-e551-07e6de5b0807"
Guid.empty
"00000000-0000-0000-0000-000000000000"
GUID
A와 string
. 귀하의 답변은 적어도를 사용하여 훨씬 더 효율적인 스토리지를 처리합니다 Uint16Array
. 이 toString
함수는 JavaScript에서 이진 표현을 사용해야합니다.object
이것은 의사 난수로 만든 버전 4 UUID를 만듭니다.
function uuid()
{
var chars = '0123456789abcdef'.split('');
var uuid = [], rnd = Math.random, r;
uuid[8] = uuid[13] = uuid[18] = uuid[23] = '-';
uuid[14] = '4'; // version 4
for (var i = 0; i < 36; i++)
{
if (!uuid[i])
{
r = 0 | rnd()*16;
uuid[i] = chars[(i == 19) ? (r & 0x3) | 0x8 : r & 0xf];
}
}
return uuid.join('');
}
다음은 생성 된 UUID 샘플입니다.
682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136
글쎄, 이것은 이미 많은 대답을 가지고 있지만 불행히도 무리에 "진정한"임의가 없습니다. 아래 버전은 broofa의 답변을 수정 한 것이지만, 가능한 경우 암호화 라이브러리를 사용하는 "진정한"임의 함수와 대체로 Alea () 함수를 포함하도록 업데이트되었습니다.
Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
Math.trueRandom = (function() {
var crypt = window.crypto || window.msCrypto;
if (crypt && crypt.getRandomValues) {
// if we have a crypto library, use it
var random = function(min, max) {
var rval = 0;
var range = max - min;
if (range < 2) {
return min;
}
var bits_needed = Math.ceil(Math.log2(range));
if (bits_needed > 53) {
throw new Exception("We cannot generate numbers larger than 53 bits.");
}
var bytes_needed = Math.ceil(bits_needed / 8);
var mask = Math.pow(2, bits_needed) - 1;
// 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111
// Create byte array and fill with N random numbers
var byteArray = new Uint8Array(bytes_needed);
crypt.getRandomValues(byteArray);
var p = (bytes_needed - 1) * 8;
for(var i = 0; i < bytes_needed; i++ ) {
rval += byteArray[i] * Math.pow(2, p);
p -= 8;
}
// Use & to apply the mask and reduce the number of recursive lookups
rval = rval & mask;
if (rval >= range) {
// Integer out of acceptable range
return random(min, max);
}
// Return an integer that falls within the range
return min + rval;
}
return function() {
var r = random(0, 1000000000) / 1000000000;
return r;
};
} else {
// From https://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/
// Johannes Baagøe <baagoe@baagoe.com>, 2010
function Mash() {
var n = 0xefc8249d;
var mash = function(data) {
data = data.toString();
for (var i = 0; i < data.length; i++) {
n += data.charCodeAt(i);
var h = 0.02519603282416938 * n;
n = h >>> 0;
h -= n;
h *= n;
n = h >>> 0;
h -= n;
n += h * 0x100000000; // 2^32
}
return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
};
mash.version = 'Mash 0.9';
return mash;
}
// From http://baagoe.com/en/RandomMusings/javascript/
function Alea() {
return (function(args) {
// Johannes Baagøe <baagoe@baagoe.com>, 2010
var s0 = 0;
var s1 = 0;
var s2 = 0;
var c = 1;
if (args.length == 0) {
args = [+new Date()];
}
var mash = Mash();
s0 = mash(' ');
s1 = mash(' ');
s2 = mash(' ');
for (var i = 0; i < args.length; i++) {
s0 -= mash(args[i]);
if (s0 < 0) {
s0 += 1;
}
s1 -= mash(args[i]);
if (s1 < 0) {
s1 += 1;
}
s2 -= mash(args[i]);
if (s2 < 0) {
s2 += 1;
}
}
mash = null;
var random = function() {
var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
s0 = s1;
s1 = s2;
return s2 = t - (c = t | 0);
};
random.uint32 = function() {
return random() * 0x100000000; // 2^32
};
random.fract53 = function() {
return random() +
(random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
};
random.version = 'Alea 0.9';
random.args = args;
return random;
}(Array.prototype.slice.call(arguments)));
};
return Alea();
}
}());
Math.guid = function() {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.trueRandom() * 16 | 0,
v = c == 'x' ? r : (r & 0x3 | 0x8);
return v.toString(16);
});
};
GitHub의 JavaScript 프로젝트-https: //github.com/LiosK/UUID.js
UUID.js JavaScript를위한 RFC 호환 UUID 생성기.
RFC 4122 http://www.ietf.org/rfc/rfc4122.txt를 참조하십시오 .
기능 RFC 4122 호환 UUID를 생성합니다.
버전 4 UUID (임의의 UUID) 및 버전 1 UUID (시간 기반 UUID)를 사용할 수 있습니다.
UUID 객체는 UUID 필드에 대한 액세스를 포함하여 UUID에 대한 다양한 액세스를 허용합니다.
JavaScript의 낮은 타임 스탬프 해상도는 난수로 보상됩니다.
// RFC 4122
//
// A UUID is 128 bits long
//
// String representation is five fields of 4, 2, 2, 2, and 6 bytes.
// Fields represented as lowercase, zero-filled, hexadecimal strings, and
// are separated by dash characters
//
// A version 4 UUID is generated by setting all but six bits to randomly
// chosen values
var uuid = [
Math.random().toString(16).slice(2, 10),
Math.random().toString(16).slice(2, 6),
// Set the four most significant bits (bits 12 through 15) of the
// time_hi_and_version field to the 4-bit version number from Section
// 4.1.3
(Math.random() * .0625 /* 0x.1 */ + .25 /* 0x.4 */).toString(16).slice(2, 6),
// Set the two most significant bits (bits 6 and 7) of the
// clock_seq_hi_and_reserved to zero and one, respectively
(Math.random() * .25 /* 0x.4 */ + .5 /* 0x.8 */).toString(16).slice(2, 6),
Math.random().toString(16).slice(2, 14)].join('-');
나는 broofa의 답변을 이해하고 싶었으므로 그것을 확장하고 의견을 추가했습니다.
var uuid = function () {
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(
/[xy]/g,
function (match) {
/*
* Create a random nibble. The two clever bits of this code:
*
* - Bitwise operations will truncate floating point numbers
* - For a bitwise OR of any x, x | 0 = x
*
* So:
*
* Math.random * 16
*
* creates a random floating point number
* between 0 (inclusive) and 16 (exclusive) and
*
* | 0
*
* truncates the floating point number into an integer.
*/
var randomNibble = Math.random() * 16 | 0;
/*
* Resolves the variant field. If the variant field (delineated
* as y in the initial string) is matched, the nibble must
* match the mask (where x is a do-not-care bit):
*
* 10xx
*
* This is achieved by performing the following operations in
* sequence (where x is an intermediate result):
*
* - x & 0x3, which is equivalent to x % 3
* - x | 0x8, which is equivalent to x + 8
*
* This results in a nibble between 8 inclusive and 11 exclusive,
* (or 1000 and 1011 in binary), all of which satisfy the variant
* field mask above.
*/
var nibble = (match == 'y') ?
(randomNibble & 0x3 | 0x8) :
randomNibble;
/*
* Ensure the nibble integer is encoded as base 16 (hexadecimal).
*/
return nibble.toString(16);
}
);
};
여기에 추가로 내 자신의 UUID / GUID 생성기를 조정 했습니다 .
다음 Kybos를 사용 하고 있습니다. 조금 더 암호화 소리로 난수 생성기를.
아래는 baagoe.com의 Mash 및 Kybos 메소드가 제외 된 스크립트입니다.
//UUID/Guid Generator
// use: UUID.create() or UUID.createSequential()
// convenience: UUID.empty, UUID.tryParse(string)
(function(w){
// From http://baagoe.com/en/RandomMusings/javascript/
// Johannes Baagøe <baagoe@baagoe.com>, 2010
//function Mash() {...};
// From http://baagoe.com/en/RandomMusings/javascript/
//function Kybos() {...};
var rnd = Kybos();
//UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
var UUID = {
"empty": "00000000-0000-0000-0000-000000000000"
,"parse": function(input) {
var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
return ret;
else
throw new Error("Unable to parse UUID");
}
,"createSequential": function() {
var ret = new Date().valueOf().toString(16).replace("-","")
for (;ret.length < 12; ret = "0" + ret);
ret = ret.substr(ret.length-12,12); //only least significant part
for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3), ret.substr(20,12)].join("-");
}
,"create": function() {
var ret = "";
for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3), ret.substr(20,12)].join("-");
}
,"random": function() {
return rnd();
}
,"tryParse": function(input) {
try {
return UUID.parse(input);
} catch(ex) {
return UUID.empty;
}
}
};
UUID["new"] = UUID.create;
w.UUID = w.Guid = UUID;
}(window || this));
속도를 고려한 rfc4122 버전 4 호환 솔루션을 원하는 경우 (Math.random ()을 거의 호출하지 않음) :
var rand = Math.random;
function UUID() {
var nbr, randStr = "";
do {
randStr += (nbr = rand()).toString(16).substr(3, 6);
} while (randStr.length < 30);
return (
randStr.substr(0, 8) + "-" +
randStr.substr(8, 4) + "-4" +
randStr.substr(12, 3) + "-" +
((nbr*4|0)+8).toString(16) + // [89ab]
randStr.substr(15, 3) + "-" +
randStr.substr(18, 12)
);
}
console.log( UUID() );
위의 기능은 속도와 임의성 사이의 균형이 맞아야합니다.
더 좋은 방법 :
function(
a,b // placeholders
){
for( // loop :)
b=a=''; // b - result , a - numeric variable
a++<36; //
b+=a*51&52 // if "a" is not 9 or 14 or 19 or 24
? // return a random number or 4
(
a^15 // if "a" is not 15
? // genetate a random number from 0 to 15
8^Math.random()*
(a^20?16:4) // unless "a" is 20, in which case a random number from 8 to 11
:
4 // otherwise 4
).toString(16)
:
'-' // in other cases (if "a" is 9,14,19,24) insert "-"
);
return b
}
최소화 :
function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}
나는 오래된 질문입니다. 완벽을 기하기 위해 환경이 SharePoint 인 경우 새 ms를 만드는 SP.Guid.newGuid
( msdn link ) 라는 유틸리티 기능이 있습니다. 이 기능은 sp.init.js 파일에 있습니다. 이 함수를 다시 작성하면 (다른 개인 함수에서 다른 종속성을 제거하기 위해) 다음과 같습니다
var newGuid = function () {
var result = '';
var hexcodes = "0123456789abcdef".split("");
for (var index = 0; index < 32; index++) {
var value = Math.floor(Math.random() * 16);
switch (index) {
case 8:
result += '-';
break;
case 12:
value = 4;
result += '-';
break;
case 16:
value = value & 3 | 8;
result += '-';
break;
case 20:
result += '-';
break;
}
result += hexcodes[value];
}
return result;
};
이 날짜는 날짜를 기준으로하며 고유성을 보장하기 위해 임의 접미사를 추가합니다. CSS 식별자에 적합합니다. 항상 같은 것을 반환하고 해킹하기 쉽습니다.
uid-139410573297741
var getUniqueId = function (prefix) {
var d = new Date().getTime();
d += (parseInt(Math.random() * 100)).toString();
if (undefined === prefix) {
prefix = 'uid-';
}
d = prefix + d;
return d;
};
지원되는 브라우저 (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome)에서 사용 crypto.getRandomValues(a)
하는 간단한 코드입니다 . 충돌을 일으킬 수 있으므로 사용을 피하십시오 (예 : Muxa 의 실제 상황에서 4000 생성 된 UUID에 대해 20 개의 충돌 ).Math.random()
function uuid() {
function randomDigit() {
if (crypto && crypto.getRandomValues) {
var rands = new Uint8Array(1);
crypto.getRandomValues(rands);
return (rands[0] % 16).toString(16);
} else {
return ((Math.random() * 16) | 0).toString(16);
}
}
var crypto = window.crypto || window.msCrypto;
return 'xxxxxxxx-xxxx-4xxx-8xxx-xxxxxxxxxxxx'.replace(/x/g, randomDigit);
}
노트:
특정 형식이 아닌 임의의 128 비트 문자열이 필요한 경우 다음을 사용할 수 있습니다.
function uuid() {
return crypto.getRandomValues(new Uint32Array(4)).join('-');
}
다음과 같은 것을 반환합니다 2350143528-4164020887-938913176-2513998651
.
Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
단지 두 개의 돌연변이를 가진 또 다른 더 읽기 쉬운 변형.
function uuid4()
{
function hex (s, b)
{
return s +
(b >>> 4 ).toString (16) + // high nibble
(b & 0b1111).toString (16); // low nibble
}
let r = crypto.getRandomValues (new Uint8Array (16));
r[6] = r[6] >>> 4 | 0b01000000; // Set type 4: 0100
r[8] = r[8] >>> 3 | 0b10000000; // Set variant: 100
return r.slice ( 0, 4).reduce (hex, '' ) +
r.slice ( 4, 6).reduce (hex, '-') +
r.slice ( 6, 8).reduce (hex, '-') +
r.slice ( 8, 10).reduce (hex, '-') +
r.slice (10, 16).reduce (hex, '-');
}
uuid 패키지를 사용하여 버전 1, 3, 4 및 5 UUID를 지원합니다 .
yarn add uuid
그리고:
const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '45745c60-7b1a-11e8-9c9c-2d42b21b1a3e'
완전히 지정된 옵션을 사용하여 수행 할 수도 있습니다.
const v1options = {
node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
clockseq: 0x1234,
msecs: new Date('2011-11-01').getTime(),
nsecs: 5678
};
uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'
이를 위해 자신의 물건을 채찍질하는 대신 둘 이상의 제공자가 유지 관리하는 잘 테스트 된 코드를 사용하는 것이 중요합니다. 이것은 X 브라우저에서 작동하지만 Y의 특이성을 고려하지 않는 가능한 가장 짧은 영리한 버전보다 가장 안정적인 코드를 선호하는 곳 중 하나입니다. 일부 사용자의 경우 개인적 으로 bower가 활성화 된 https://github.com/aurigadl/uuid-js 에서 uuid-js를 사용하므로 쉽게 업데이트 할 수 있습니다.