Làm thế nào để tạo GUID / UUID?


4180

Tôi đang cố gắng tạo các mã định danh duy nhất trên toàn cầu trong JavaScript. Tôi không chắc chắn những thói quen nào có sẵn trên tất cả các trình duyệt, mức độ "ngẫu nhiên" và khởi tạo trình tạo số ngẫu nhiên tích hợp, v.v.

GUID / UUID phải có ít nhất 32 ký tự và phải ở trong phạm vi ASCII để tránh rắc rối khi chuyển chúng xung quanh.


13
HƯỚNG DẪN khi được lặp lại dưới dạng chuỗi có ít nhất 36 và không quá 38 ký tự và khớp với mẫu ^ \ {? [A-zA-Z0-9] {36}? \} $ Và do đó luôn luôn là ascii.
AnthonyWJones

2
David Bau cung cấp một trình tạo số ngẫu nhiên có thể tạo hạt tốt hơn nhiều tại davidbau.com/archives/2010/01/30/NH Tôi đã viết một cách tiếp cận hơi khác để tạo UUID tại blog.cozi.com/tech/2010/04/generating- uuids-in-javascript.html
George V. Reilly

Điều kỳ lạ là chưa có ai đề cập đến vấn đề này nhưng về tính đầy đủ, có rất nhiều trình tạo hướng dẫn trên npm Tôi sẵn sàng đặt cược hầu hết chúng cũng hoạt động trên trình duyệt.
George Mauer

Câu trả lời:


2339

UUID (IDentifier duy nhất toàn cầu), còn được gọi là GUID (IDentifier duy nhất toàn cầu), theo RFC 4122 , là các định danh được thiết kế để cung cấp một số đảm bảo duy nhất.

Mặc dù có thể triển khai các UUID tuân thủ RFC trong một vài dòng JS (Ví dụ: xem câu trả lời của @ broofa , bên dưới), có một số cạm bẫy phổ biến:

  • Định dạng id không hợp lệ (UUID phải có dạng " xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx", trong đó x là một trong [0-9, af] M là một trong [1-5] và N là [8, 9, a hoặc b]
  • Sử dụng nguồn ngẫu nhiên chất lượng thấp (như Math.random)

Do đó, các nhà phát triển viết mã cho môi trường sản xuất được khuyến khích sử dụng một triển khai nghiêm ngặt, được duy trì tốt như mô-đun uuid .


186
Trên thực tế, RFC cho phép các UUID được tạo từ các số ngẫu nhiên. Bạn chỉ cần xoay một vài bit để xác định nó là như vậy. Xem phần 4.4. Các thuật toán để tạo UUID từ các số ngẫu nhiên hoặc giả ngẫu nhiên: rfc-archive.org/getrfc.php?rfc=4122
Jason DeFontes

Dựa trên tất cả mọi thứ trong luồng này, tôi đã tạo một phiên bản nhanh gấp đôi so với biến thể "e7" bên dưới, mã hóa mạnh và hoạt động trên tất cả các trình duyệt và nút chính. Nó quá lớn để bao gồm ở đây, vì vậy hãy tìm một câu trả lời mới với tên của tôi vào ngày 17 tháng 5 năm 2020.
Bennett Barouch

node-uuid giờ đã trở thành uuid (sau khi hợp nhất với dự án sau)
Catweazle

4115

Đối với giải pháp tương thích RFC4122 phiên bản 4, giải pháp một lớp (ish) này là nhỏ gọn nhất tôi có thể nghĩ ra:

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());

Cập nhật, 2015-06 / 02 : Lưu ý rằng tính duy nhất của UUID phụ thuộc rất nhiều vào trình tạo số ngẫu nhiên cơ bản (RNG). Các giải pháp trên sử dụng Math.random()cho ngắn gọn, tuy nhiênMath.random()không đảm bảo được một RNG chất lượng cao. Xem bài viết tuyệt vời của Adam Hyland trên Math.random () để biết chi tiết. Để có giải pháp mạnh mẽ hơn, hãy cân nhắc sử dụng mô-đun uuid , sử dụng API RNG chất lượng cao hơn.

Cập nhật, 2015-08-26 : Như một lưu ý phụ, ý chính này mô tả cách xác định số lượng ID có thể được tạo trước khi đạt đến xác suất va chạm nhất định. Ví dụ: với 3.26x10 15 phiên bản 4 RFC4122 UUID, bạn có cơ hội va chạm 1 triệu.

Cập nhật, 2017-06-28 : Một bài viết hay từ các nhà phát triển Chrome thảo luận về trạng thái chất lượng PRNG của Math.random trong Chrome, Firefox và Safari. tl; dr - Tính đến cuối năm 2015, nó "khá tốt", nhưng không phải là chất lượng mật mã. Để giải quyết vấn đề đó, đây là phiên bản cập nhật của giải pháp trên sử dụng ES6, cryptoAPI và một chút thuật sĩ JS mà tôi không thể tin tưởng :

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ập nhật, 2020-01-06 : Có một đề xuất trong các công trình cho một uuidmô-đun chuẩn như là một phần của ngôn ngữ JS


30
Tôi đã đăng câu hỏi về va chạm stackoverflow.com/questions/6906916/ từ
Muxa

4
@marc - Chất lượng của Math.random () là một mối quan tâm. Nhưng không có phân tích chi tiết về việc triển khai cơ bản, gần như chắc chắn thay đổi trình duyệt x, chúng ta không thể biết được tỷ lệ va chạm thực tế. Vì vậy, để đơn giản, tôi giả sử một nguồn ngẫu nhiên lý tưởng. Nhưng, vâng, đó có thể là một giả định nguy hiểm vì vấn đề nổi bật của muxa. Đó cũng là lý do tại sao trong nút-uuid ( github.com/broofa/node-uuid ) Tôi thích các API khác đảm bảo tính ngẫu nhiên về chất lượng mật mã so với Math.random (), mặc dù hiệu năng phải chịu đựng.
broalid

144
Chắc chắn câu trả lời cho câu hỏi của @ Muxa là 'không'? Không bao giờ thực sự an toàn để tin tưởng một cái gì đó đến từ khách hàng. Tôi đoán nó phụ thuộc vào khả năng người dùng của bạn sẽ đưa ra một bảng điều khiển javascript và thay đổi thủ công biến đó thành thứ gì đó họ muốn. Hoặc họ có thể gửi lại cho bạn id mà họ muốn. Nó cũng phụ thuộc vào việc người dùng chọn ID của chính họ có gây ra lỗ hổng hay không. Dù bằng cách nào, nếu đó là một ID số ngẫu nhiên đang đi vào một bảng, tôi có thể sẽ tạo ra phía máy chủ, để tôi biết rằng tôi có quyền kiểm soát quá trình.
Cam Jackson

36
@DrewNoakes - UUID không chỉ là một chuỗi hoàn toàn ngẫu nhiên. "4" là phiên bản uuid (4 = "ngẫu nhiên"). Dấu "y" nơi biến thể uuid (bố cục trường, về cơ bản) cần được nhúng. Xem các phần 4.1.1 và 4.1.3 của ietf.org/rfc/rfc4122.txt để biết thêm thông tin.
broofa

5
Tại sao c== 'x'thay vì c === 'x'. Vì jshint thất bại.
Fizer Khan

810

Tôi thực sự thích câu trả lời của Broofa sạch sẽ như thế nào , nhưng thật không may là việc triển khai kémMath.random để lại cơ hội va chạm.

Đây là một giải pháp tương thích RFC4122 phiên bản 4 tương tự giải quyết vấn đề đó bằng cách bù đắp 13 số hex đầu tiên bằng một phần hex của dấu thời gian và một lần làm cạn kiệt một phần hex của micrô giây kể từ khi tải trang. Theo cách đó, ngay cả khi Math.randomở trên cùng một hạt giống, cả hai khách hàng sẽ phải tạo UUID với cùng số micrô giây kể từ khi tải trang (nếu thời gian hiệu suất cao được hỗ trợ) VÀ ở cùng một mili giây (hoặc hơn 10.000 năm sau) nhận cùng 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())


Đây là một bí quyết để kiểm tra.


31
Hãy nhớ rằng, new Date().getTime()không được cập nhật mỗi mili giây. Tôi không chắc điều này ảnh hưởng đến tính ngẫu nhiên dự kiến ​​của thuật toán của bạn.
devios1

84
hiệu suất.now sẽ còn tốt hơn. Không giống như Date.now, dấu thời gian được trả về performance.now()không bị giới hạn ở độ phân giải một mili giây. Thay vào đó, chúng biểu thị thời gian dưới dạng số dấu phẩy động với độ chính xác lên đến micro giây . Cũng không giống như Date.now, các giá trị được trả về bởi Performance.now () luôn tăng với tốc độ không đổi , độc lập với đồng hồ hệ thống có thể được điều chỉnh thủ công hoặc bị lệch bởi phần mềm như Giao thức thời gian mạng.
daniellmb

6
@daniellmb Có lẽ bạn nên liên kết với MDN hoặc người khác để hiển thị tài liệu thực chứ không phải là một polyfill;)
Martin

2
Tôi có thể biết làm tròn sử dụng là d = Math.floor(d/16);gì?
Praveen

2
@Praveen Thao tác đó dịch chuyển dấu thời gian một chữ số hex sang phải và bỏ phần còn lại. Mục đích của nó là để loại bỏ chữ số hex mà chúng ta vừa sử dụng (số ít quan trọng nhất) và sẵn sàng cho lần lặp tiếp theo.
Briguy37

431

Thật vậy, câu trả lời của broalid khá lắt léo - thông minh một cách ấn tượng, thực sự ... tuân thủ rfc4122, hơi dễ đọc và nhỏ gọn. Tuyệt vời!

Nhưng nếu bạn đang nhìn vào mà biểu hiện thường xuyên, những người nhiều replace()callbacks, toString()'s và Math.random()gọi hàm (nơi anh ta chỉ sử dụng 4 bit của kết quả và lãng phí phần còn lại), bạn có thể bắt đầu tự hỏi về hiệu suất. Thật vậy, joelpt thậm chí đã quyết định tung ra RFC cho tốc độ GUID chung vớigenerateQuickGUID .

Nhưng, chúng ta có thể đạt được tốc độ tuân thủ RFC không? Tôi nói "có! Chúng ta có thể duy trì khả năng đọc? Chà ... Không hẳn, nhưng thật dễ nếu bạn làm theo.

Nhưng trước tiên, kết quả của tôi, so với broofa, guid(câu trả lời được chấp nhận) và không tuân thủ 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.

Vì vậy, bằng lặp thứ 6 của tôi về tối ưu hóa, tôi đánh bại câu trả lời phổ biến nhất hơn 12X , câu trả lời được chấp nhận bởi hơn 9X , và câu trả lời nhanh không tuân thủ bởi 2-3X . Và tôi vẫn tuân thủ rfc4122.

Quan tâm đến làm thế nào? Tôi đã đặt nguồn đầy đủ trên http://jsfiddle.net/jcward/7hyaC/3/ và trên http://jsperf.com/uuid-generator-opt/4

Để giải thích, hãy bắt đầu với mã của 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())

Vì vậy, nó thay thế xbằng bất kỳ chữ số hex ngẫu nhiên nào, ybằng dữ liệu ngẫu nhiên (ngoại trừ việc buộc 2 bit 10trên cùng theo thông số RFC) và regex không khớp với -hoặc4 ký tự, vì vậy anh ta không phải xử lý chúng. Rất, rất lắt léo.

Điều đầu tiên cần biết là các lệnh gọi hàm rất đắt, cũng như các biểu thức thông thường (mặc dù anh ta chỉ sử dụng 1, nhưng nó có 32 cuộc gọi lại, một cuộc gọi cho mỗi trận đấu và trong mỗi 32 cuộc gọi lại, nó gọi Math.random () và v. toString (16)).

Bước đầu tiên hướng tới hiệu suất là loại bỏ RegEx và các hàm gọi lại của nó và sử dụng một vòng lặp đơn giản để thay thế. Điều này có nghĩa là chúng ta phải đối phó với -và các 4nhân vật trong khi broalid thì không. Ngoài ra, lưu ý rằng chúng ta có thể sử dụng lập chỉ mục Chuỗi Array để giữ kiến ​​trúc mẫu Chuỗi trơn bóng của mình:

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())

Về cơ bản, logic bên trong tương tự, ngoại trừ chúng tôi kiểm tra -hoặc 4và sử dụng vòng lặp while (thay vì replace()gọi lại) giúp chúng tôi cải thiện gần gấp 3 lần!

Bước tiếp theo là một bước nhỏ trên máy tính để bàn nhưng tạo ra sự khác biệt khá lớn trên thiết bị di động. Chúng ta hãy thực hiện ít cuộc gọi Math.random () hơn và sử dụng tất cả các bit ngẫu nhiên đó thay vì ném 87% trong số chúng với một bộ đệm ngẫu nhiên được chuyển ra mỗi lần lặp. Chúng ta cũng hãy di chuyển định nghĩa mẫu đó ra khỏi vòng lặp, chỉ trong trường hợp nó giúp:

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())

Điều này giúp chúng tôi tiết kiệm 10-30% tùy thuộc vào nền tảng. Không tệ. Nhưng bước tiến lớn tiếp theo sẽ loại bỏ chức năng gọi toString hoàn toàn với một cổ điển tối ưu hóa - bảng tra cứu. Bảng tra cứu 16 phần tử đơn giản sẽ thực hiện công việc của toString (16) trong thời gian ngắn hơn nhiều:

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())

Tối ưu hóa tiếp theo là một cổ điển khác. Vì chúng ta chỉ xử lý 4 bit đầu ra trong mỗi lần lặp lặp, nên hãy cắt một nửa số vòng lặp và xử lý 8 bit mỗi lần lặp. Điều này thật khó khăn vì chúng ta vẫn phải xử lý các vị trí bit tuân thủ RFC, nhưng nó không quá khó. Sau đó, chúng tôi phải tạo một bảng tra cứu lớn hơn (16x16 hoặc 256) để lưu trữ 0x00 - 0xff và chúng tôi chỉ xây dựng nó một lần, bên ngoài hàm 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())

Tôi đã thử một e6 () xử lý 16 bit cùng một lúc, vẫn sử dụng LUT 256 phần tử và nó cho thấy lợi nhuận tối ưu hóa giảm dần. Mặc dù nó có số lần lặp ít hơn, logic bên trong rất phức tạp do quá trình xử lý tăng lên và nó thực hiện tương tự trên máy tính để bàn và chỉ nhanh hơn ~ 10% trên thiết bị di động.

Kỹ thuật tối ưu hóa cuối cùng để áp dụng - bỏ vòng lặp. Vì chúng tôi lặp một số lần cố định, về mặt kỹ thuật, chúng tôi có thể viết tất cả những điều này bằng tay. Tôi đã thử điều này một lần với một biến ngẫu nhiên r duy nhất mà tôi tiếp tục gán lại và hiệu suất giảm dần. Nhưng với bốn biến được gán dữ liệu ngẫu nhiên ở phía trước, sau đó sử dụng bảng tra cứu và áp dụng các bit RFC thích hợp, phiên bản này hút tất cả:

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())

Đã sửa đổi: http://jcward.com/UUID.js -UUID.generate()

Điều buồn cười là, tạo ra 16 byte dữ liệu ngẫu nhiên là phần dễ dàng. Toàn bộ thủ thuật là thể hiện nó ở định dạng Chuỗi với tuân thủ RFC và nó được thực hiện chặt chẽ nhất với 16 byte dữ liệu ngẫu nhiên, một vòng lặp và bảng tra cứu không được kiểm soát.

Tôi hy vọng logic của tôi là chính xác - rất dễ phạm sai lầm trong loại công việc tẻ nhạt này. Nhưng đầu ra có vẻ tốt với tôi. Tôi hy vọng bạn thích chuyến đi điên rồ này thông qua tối ưu hóa mã!

Được thông báo: mục tiêu chính của tôi là thể hiện và dạy các chiến lược tối ưu hóa tiềm năng. Các câu trả lời khác bao gồm các chủ đề quan trọng như va chạm và các số thực sự ngẫu nhiên, rất quan trọng để tạo ra các UUID tốt.


14
Mã này vẫn có một vài lỗi: các Math.random()*0xFFFFFFFFdòng nên Math.random()*0x100000000hoàn toàn ngẫu nhiên và >>>0nên được sử dụng thay vì |0giữ các giá trị không dấu (mặc dù với mã hiện tại tôi nghĩ rằng nó sẽ ổn ngay cả khi chúng được ký). Cuối cùng, nó sẽ là một ý tưởng rất tốt trong những ngày này để sử dụng window.crypto.getRandomValuesnếu có sẵn và chỉ quay lại Math.random nếu thực sự cần thiết. Math.random có ​​thể có ít hơn 128 bit entropy, trong trường hợp này, điều này sẽ dễ bị va chạm hơn mức cần thiết.
Dave

Dựa trên mọi thứ đã có trên chuỗi này, tôi đã xây dựng thứ gì đó nhanh gấp đôi "e7", di động tất cả các môi trường, bao gồm cả nút và được nâng cấp từ Math.random () thành tính ngẫu nhiên về sức mạnh của tiền điện tử. Bạn có thể không nghĩ rằng uuid cần sức mạnh của tiền điện tử, nhưng điều đó có nghĩa là thậm chí ít có khả năng xảy ra va chạm, đó là toàn bộ quan điểm của một uuid. Quá lớn để phù hợp với một bình luận, tôi đã đăng nó một cách riêng biệt.
Bennett Barouch

164

Đây là một số mã dựa trên RFC 4122 , phần 4.4 (Thuật toán tạo UUID từ số ngẫu nhiên thực hoặc ngẫu nhiên giả).

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;
}

4
Bạn nên khai báo kích thước mảng trước thay vì kích thước nó một cách linh hoạt khi bạn xây dựng GUID. var s = new Array(36);
MgSam

1
Tôi nghĩ rằng có một lỗi rất nhỏ trong dòng đặt bit bit 6-7 của clock_seq_hi_and_reserved thành 01. Vì s [19] là ký tự '0' .. 'f' chứ không phải int 0x0..0xf, (s [19] & 0x3) | 0x8 sẽ không được phân phối ngẫu nhiên - nó sẽ có xu hướng tạo ra nhiều '9 và ít hơn' b '. Điều này chỉ tạo ra sự khác biệt nếu bạn quan tâm đến việc phân phối ngẫu nhiên vì một số lý do.
John Velonis

153
let uniqueId = Math.random().toString(36).substring(2) + Date.now().toString(36);

Nếu ID được tạo cách nhau hơn 1 mili giây, chúng là 100% duy nhất.

Nếu hai ID được tạo trong khoảng thời gian ngắn hơn và giả sử rằng phương thức ngẫu nhiên thực sự ngẫu nhiên, thì điều này sẽ tạo ra ID có khả năng là 99.99999999999999999% duy nhất trên toàn cầu (va chạm trong 1 trên 10 ^ 15)

Bạn có thể tăng số này bằng cách thêm nhiều chữ số, nhưng để tạo ID duy nhất 100%, bạn sẽ cần sử dụng bộ đếm toàn cầu.

nếu bạn cần khả năng tương thích RFC, định dạng này sẽ vượt qua dưới dạng phiên bản hợp lệ 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('-');

Chỉnh sửa: Đoạn mã trên tuân theo ý định, nhưng không phải là chữ cái của RFC. Trong số những khác biệt khác, nó có một vài chữ số ngẫu nhiên ngắn. (Thêm nhiều chữ số ngẫu nhiên hơn nếu bạn cần) Ưu điểm là nó rất nhanh :) Bạn có thể kiểm tra tính hợp lệ của GUID tại đây


4
Đây không phải là UUID?
Marco Kerwitz

Số UUID / GUID là số 122 bit (+ sáu bit dành riêng). nó có thể đảm bảo tính duy nhất thông qua dịch vụ truy cập toàn cầu, nhưng thường thì nó chuyển tiếp về thời gian, địa chỉ MAC và tính ngẫu nhiên. UUID không phải là ngẫu nhiên! UID tôi đề nghị ở đây không được nén hoàn toàn. Bạn có thể nén nó, thành một số nguyên 122 bit, thêm 6 bit được xác định trước và các bit ngẫu nhiên bổ sung (loại bỏ một vài bit hẹn giờ) và cuối cùng bạn sẽ có một UUID / GUID được tạo thành hoàn hảo, sau đó bạn sẽ phải chuyển đổi thành hex. Đối với tôi điều đó không thực sự thêm bất cứ điều gì ngoài việc tuân thủ độ dài của ID.
Simon Rigét

5
Chuyển tiếp địa chỉ MAC cho tính duy nhất trên máy ảo là một ý tưởng tồi!
Simon Rigét

1
Tôi làm một cái gì đó như thế này, nhưng với các nhân vật hàng đầu và một số dấu gạch ngang (ví dụ [slug, date, random].join("_")để tạo usr_1dcn27itd_hj6onj6phr. Nó làm cho nó để id cũng tăng gấp đôi như một trường "được tạo tại"
Seph Reed

95

GUID nhanh nhất như phương thức tạo chuỗi theo định dạng XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Điều này không tạo GUID tuân thủ tiêu chuẩn.

Mười triệu lần thực hiện việc triển khai này chỉ mất 32,5 giây, đây là tốc độ nhanh nhất tôi từng thấy trong trình duyệt (giải pháp duy nhất không có vòng lặp / lặp).

Hàm này đơn giản như:

/**
 * 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();
}

Để kiểm tra hiệu suất, bạn có thể chạy mã này:

console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    guid(); 
};
console.timeEnd('t');

Tôi chắc rằng hầu hết các bạn sẽ hiểu những gì tôi đã làm ở đó, nhưng có lẽ có ít nhất một người sẽ cần một lời giải thích:

Thuật toán:

  • Các Math.random()chức năng trả về một số thập phân giữa 0 và 1 với 16 chữ số sau dấu thập phân phần (ví dụ 0.4363923368509859).
  • Sau đó, chúng tôi lấy số này và chuyển đổi nó thành một chuỗi với cơ sở 16 (từ ví dụ trên chúng tôi sẽ nhận được 0.6fb7687f).
    Math.random().toString(16).
  • Sau đó, chúng tôi cắt bỏ 0.tiền tố ( 0.6fb7687f=> 6fb7687f) và nhận được một chuỗi có tám ký tự thập lục phân dài.
    (Math.random().toString(16).substr(2,8).
  • Đôi khi Math.random()hàm sẽ trả về số ngắn hơn (ví dụ 0.4363), do các số 0 ở cuối (từ ví dụ trên, thực tế là số này 0.4363000000000000). Đó là lý do tại sao tôi nối thêm chuỗi này "000000000"(một chuỗi có chín số không) và sau đó cắt nó bằng chuỗisubstr() chức năng để làm cho nó có chín ký tự chính xác (điền các số không ở bên phải).
  • Lý do để thêm chính xác chín số không là do trường hợp xấu hơn, đó là khi Math.random()hàm sẽ trả về chính xác 0 hoặc 1 (xác suất 1/10 ^ 16 cho mỗi một trong số chúng). Đó là lý do tại sao chúng ta cần thêm chín số không vào nó ( "0"+"000000000"hoặc "1"+"000000000"), và sau đó cắt nó khỏi chỉ số thứ hai (ký tự thứ 3) với độ dài tám ký tự. Đối với các trường hợp còn lại, việc thêm số không sẽ không gây hại cho kết quả vì dù sao nó cũng bị cắt.
    Math.random().toString(16)+"000000000").substr(2,8).

Việc lắp ráp:

  • GUID có định dạng sau XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • Tôi chia GUID thành 4 mảnh, mỗi mảnh chia thành 2 loại (hoặc định dạng): XXXXXXXX-XXXX-XXXX.
  • Bây giờ tôi đang xây dựng GUID bằng cách sử dụng 2 loại này để lắp ráp GUID với 4 cuộc gọi, như sau : XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Để khác nhau giữa hai loại này, tôi đã thêm một tham số cờ cho hàm tạo cặp _p8(s), stham số này cho biết chức năng có thêm dấu gạch ngang hay không.
  • Cuối cùng, chúng tôi xây dựng GUID với chuỗi sau : _p8() + _p8(true) + _p8(true) + _p8(), và trả lại.

Liên kết đến bài đăng này trên blog của tôi

Thưởng thức! :-)


13
Việc thực hiện này là không chính xác. Một số ký tự của GUID yêu cầu xử lý đặc biệt (ví dụ chữ số thứ 13 cần là số 4).
JLRishe

67

Đây là sự kết hợp của câu trả lời được bình chọn hàng đầu , với cách giải quyết cho các va chạm của 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);
        });
    };

Trên jsbin nếu bạn muốn kiểm tra nó.


3
lưu ý rằng phiên bản đầu tiên, một `window.crypto.getRandomValues , does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` nó mang lại xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
nhân

66

Đây là một triển khai hoàn toàn không tuân thủ nhưng rất hiệu quả để tạo ra một định danh duy nhất giống như GUID an toàn ASCII.

function generateQuickGuid() {
    return Math.random().toString(36).substring(2, 15) +
        Math.random().toString(36).substring(2, 15);
}

Tạo 26 ký tự [a-z0-9], thu được UID vừa ngắn vừa độc đáo hơn GUID tuân thủ RFC. Dấu gạch ngang có thể được thêm vào một cách tầm thường nếu vấn đề dễ đọc của con người.

Dưới đây là các ví dụ sử dụng và thời gian cho chức năng này và một số câu trả lời khác của câu hỏi này. Thời gian được thực hiện trong Chrome m25, 10 triệu lần lặp mỗi lần.

>>> 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

Đây là mã thời gian.

var r;
console.time('t'); 
for (var i = 0; i < 10000000; i++) { 
    r = FuncToTest(); 
};
console.timeEnd('t');

62

Đây là một giải pháp ngày 9 tháng 10 năm 2011 từ một bình luận của người dùng jed tại https://gist.github.com/982883 :

UUIDv4 = function b(a){return a?(a^Math.random()*16>>a/4).toString(16):([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g,b)}

Điều này hoàn thành mục tiêu giống như câu trả lời được xếp hạng cao nhất hiện tại , nhưng trong hơn 50 byte bằng cách khai thác sự ép buộc, đệ quy và ký hiệu theo cấp số nhân. Đối với những người tò mò về cách thức hoạt động của nó, đây là dạng chú thích của phiên bản cũ hơn của hàm:

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
      )
}

52

Từ blog kỹ thuật của sagi shkedy :

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;
}

Có các phương pháp khác liên quan đến việc sử dụng điều khiển ActiveX, nhưng tránh xa những điều này!

Chỉnh sửa: Tôi nghĩ rằng đáng để chỉ ra rằng không có trình tạo GUID nào có thể đảm bảo các khóa duy nhất (kiểm tra bài viết trên wikipedia ). Luôn có cơ hội va chạm. GUID chỉ đơn giản là cung cấp một vũ trụ đủ lớn để giảm sự thay đổi va chạm xuống gần như không.


8
Lưu ý rằng đây không phải là GUID theo nghĩa kỹ thuật, vì nó không có gì để đảm bảo tính duy nhất. Điều đó có thể hoặc không quan trọng tùy thuộc vào ứng dụng của bạn.
Stephen Deken

2
Một lưu ý nhanh về hiệu suất. Giải pháp này tạo tổng cộng 36 chuỗi để có một kết quả duy nhất. Nếu hiệu suất là quan trọng, hãy xem xét việc tạo một mảng và tham gia theo khuyến nghị của: tinyurl.com/y37xtx Nghiên cứu thêm cho thấy điều đó có thể không quan trọng, vì vậy YMMV: tinyurl.com/3l7945
Brandon DuRette

2
Về tính độc đáo, đáng chú ý là phiên bản 1.3 và 5 UUID mang tính quyết định theo cách mà phiên bản 4 không có. Nếu các đầu vào cho các trình tạo uuid này - id nút trong v1, không gian tên và tên trong v3 và v5 - là duy nhất (như chúng được cho là), thì UUID kết quả là duy nhất. Về lý thuyết, dù sao đi nữa.
broalid

41

Bạn có thể sử dụng nút-uuid ( https://github.com/kelekunch/node-uuid )

Thế hệ đơn giản, nhanh chóng của RFC4122 UUIDS.

Đặc trưng:

  • Tạo RFC4122 phiên bản 1 hoặc 4 UUID
  • Chạy trong node.js và trình duyệt.
  • Thế hệ # ngẫu nhiên mạnh về mật mã trên các nền tảng hỗ trợ.
  • Dấu chân nhỏ (Muốn một cái gì đó nhỏ hơn? Hãy xem cái này! )

Cài đặt bằng NPM:

npm install uuid

Hoặc sử dụng uuid qua trình duyệt:

Tải xuống tệp thô (uuid v1): https://raw.githubusercontent.com/kelekunch/node-uuid/master/v1.js Tải xuống tệp thô (uuid v4): https://raw.githubusercontent.com/kelekunch/node -uuid / master / v4.js


Muốn thậm chí nhỏ hơn? Hãy xem điều này: https://gist.github.com/jed/982883


Sử dụng:

// 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();

34
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);
    });
};

BIÊN TẬP:

Xem lại dự án của tôi đã sử dụng chức năng này và không thích sự dài dòng. - Nhưng cần sự ngẫu nhiên thích hợp.

Một phiên bản dựa trên câu trả lời của Briguy37 và một số toán tử bitwise để trích xuất các cửa sổ có kích thước nhỏ từ bộ đệm.

Phải tuân thủ lược đồ RFC Loại 4 (ngẫu nhiên), vì tôi đã gặp sự cố lần trước khi phân tích cú pháp không tuân thủ UUID của Java.


31

Mô-đun JavaScript đơn giản là sự kết hợp của các câu trả lời hay nhất trong chuỗi này.

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());

Sử dụng:

Guid.newGuid ()

"c6c2d12f-d76b-5739-e551-07e6de5b0807"

Hướng dẫn

"00000000-0000-0000-0000-000000000000"


1
Điều gì đang làm phiền về tất cả các câu trả lời là nó có vẻ ok cho hoạt Javascript để lưu trữ các GUIDnhư một string. Câu trả lời của bạn ít nhất đã khắc phục các nhiều lưu trữ hiệu quả hơn bằng cách sử dụng Uint16Array. Các toStringchức năng nên được sử dụng các đại diện nhị phân trong một hoạt Javascriptobject
Sebastian

Các UUID này được tạo bởi mã này là tuân thủ yếu-nhưng-RFC (_guid) hoặc mạnh-nhưng-không-không-tuân thủ RFC (_cryptoGuid). Cái trước sử dụng Math.random (), hiện được biết đến là một RNG nghèo. Cái sau không thể thiết lập các phiên bản và các trường biến thể.
broalid

@broofa - Bạn có đề xuất gì để làm cho nó mạnh mẽ tuân thủ RFC? Và tại sao _cryptoGuid không tuân thủ RFC?
Matt

@Matt _cryptoGuid () đặt ngẫu nhiên tất cả 128 bit, có nghĩa là nó không đặt các phiên bản và trường biến thể như được mô tả trong RFC. Xem triển khai thay thế uuidv4 () sử dụng crypto.getRandomValues ​​() trong câu trả lời được bình chọn hàng đầu của tôi, ở trên, để triển khai mạnh mẽ + tuân thủ.
broifer

29

Điều này tạo UUID phiên bản 4 (được tạo từ các số ngẫu nhiên giả):

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('');
}

Dưới đây là mẫu UUID được tạo:

682db637-0f31-4847-9cdf-25ba9613a75c
97d19478-3ab2-4aa1-b8cc-a1c3540f54aa
2eed04c9-2692-456d-a0fd-51012f947136

28

Chà, điều này đã có sẵn một loạt các câu trả lời, nhưng thật không may, không có ngẫu nhiên "thực sự" trong bó. Phiên bản dưới đây là bản phóng tác của câu trả lời của broofa, nhưng được cập nhật để bao gồm một hàm ngẫu nhiên "thật" sử dụng các thư viện tiền điện tử có sẵn và hàm Alea () làm dự phòng.

  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);
  });
};

27

Dự án JavaScript trên GitHub - https://github.com/LiosK/UUID.js

UUID.js Trình tạo UUID tuân thủ RFC cho JavaScript.

Xem RFC 4122 http://www.ietf.org/rfc/rfc4122.txt .

Tính năng Tạo UUID tuân thủ RFC 4122.

UUID phiên bản 4 (UUID từ số ngẫu nhiên) và UUID phiên bản 1 (UUID dựa trên thời gian) có sẵn.

Đối tượng UUID cho phép nhiều quyền truy cập vào UUID bao gồm quyền truy cập vào các trường UUID.

Độ phân giải dấu thời gian thấp của JavaScript được bù bằng số ngẫu nhiên.


21
  // 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('-');

16

Tôi muốn hiểu câu trả lời của broofa, vì vậy tôi đã mở rộng nó và thêm ý kiến:

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);
        }
    );
};

Cảm ơn bạn đã mô tả chi tiết! Cụ thể nibble lồng giữa 8 và 11 với giải thích tương đương là siêu hữu ích.
Egor Litvinchuk

15

Điều chỉnh trình tạo UUID / GUID của riêng tôi với một số tính năng bổ sung tại đây .

Tôi đang sử dụng trình tạo số ngẫu nhiên Kybos sau đây để có âm thanh mật mã hơn một chút.

Dưới đây là tập lệnh của tôi với các phương thức Mash và Kybos từ baagoe.com bị loại trừ.

//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));

15

Đối với những người muốn một giải pháp tuân thủ rfc4122 phiên bản 4 với các cân nhắc về tốc độ (vài cuộc gọi đến 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() );

Các chức năng trên nên có một sự cân bằng hợp lý giữa tốc độ và tính ngẫu nhiên.


13

Mẫu ES6

const guid=()=> {
  const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);     
  return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}

12

Cách tốt hơn:

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
 }

Tối thiểu hóa:

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}

11

Tôi biết, đó là một câu hỏi cũ. Để hoàn thiện, nếu môi trường của bạn là SharePoint, có một chức năng tiện ích được gọi là SP.Guid.newGuid( liên kết msdn ) tạo ra một hướng dẫn mới. Hàm này nằm trong tệp sp.init.js. Nếu bạn viết lại chức năng này (để loại bỏ một số phụ thuộc khác khỏi các chức năng riêng tư khác), nó sẽ giống như sau:

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;
};

11

Cái này dựa trên ngày tháng và thêm một hậu tố ngẫu nhiên để "đảm bảo" tính duy nhất. Hoạt động tốt cho định danh css. Nó luôn trả về một cái gì đó như và rất dễ hack:

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;
        };

11

Mã đơn giản sử dụng crypto.getRandomValues(a)trên các trình duyệt được hỗ trợ (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Tránh sử dụng Math.random()vì điều đó có thể gây ra va chạm (ví dụ 20 va chạm cho 4000 uuids được tạo trong tình huống thực tế của Muxa ).

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);
}

Ghi chú:

  • Tối ưu hóa cho khả năng đọc mã không phải tốc độ, vì vậy phù hợp để nói vài trăm uuid mỗi giây. Tạo khoảng 10000 uuid () mỗi giây trong Chromium trên máy tính xách tay của tôi bằng cách sử dụng http://jsbin.com/fuwigo/1 để đo hiệu suất.
  • Chỉ sử dụng 8 cho "y" vì điều đó giúp đơn giản hóa khả năng đọc mã (y được phép là 8, 9, A hoặc B).

11

Nếu bạn chỉ cần một chuỗi 128 bit ngẫu nhiên không có định dạng cụ thể, bạn có thể sử dụng:

function uuid() {
    return crypto.getRandomValues(new Uint32Array(4)).join('-');
}

Mà sẽ trả lại một cái gì đó như 2350143528-4164020887-938913176-2513998651.


BTW, tại sao nó chỉ tạo ra số và không phải là ký tự? kém an toàn hơn nhiều
vsync

1
bạn cũng có thể thêm các ký tự (chữ cái) như thế này:Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
magikMaker

11

Chỉ là một biến thể dễ đọc hơn với chỉ hai đột biến.

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, '-');
}

Chà, hầu hết các nhà phát triển js đều là nhà phát triển web và chúng tôi sẽ không hiểu các nhà khai thác bitwise làm gì, vì chúng tôi không sử dụng họ hầu hết thời gian chúng tôi phát triển. Thật ra tôi không bao giờ cần bất kỳ ai trong số họ, và tôi là một js dev kể từ năm 97. Vì vậy, mã ví dụ của bạn vẫn hoàn toàn không thể đọc được đối với nhà phát triển web trung bình sẽ đọc nó. Chưa kể rằng bạn vẫn sử dụng các tên biến đơn, điều này làm cho nó thậm chí còn khó hiểu hơn. Có thể đọc Clean Code, có thể giúp: amazon.com/Clean-Code-Handbook-Software-Ccraft
Skill / dp / giả

@ inf3rno không bash anh ta, tất cả các giải pháp được đề xuất trong chủ đề này là khó hiểu nhưng chúng là câu trả lời chính xác khi xem xét câu hỏi là có một loại sắp xếp. đó là những gì một lớp lót là khó hiểu. họ không đủ khả năng để có thể đọc được cho nhà phát triển trung bình nhưng họ lưu màn hình bất động sản nơi một nhận xét đơn giản trước đó sẽ làm. Và kết quả là, thay vào đó, nó sẽ dễ đọc hơn theo cách đó nếu nó đã ở trong "mã có thể đọc được".
tatsu

Ngẫu nhiên! = Unique
user1529413

@ user1529413 Có. Tính duy nhất đòi hỏi một chỉ số.
ceving

Đây là câu trả lời yêu thích của tôi, bởi vì nó xây dựng UUID dưới dạng giá trị 16 byte (128 bit) và không phải là dạng đọc được xê-ri hóa, đẹp mắt. Thật dễ dàng để bỏ các công cụ chuỗi và chỉ cần đặt các bit chính xác của 128bit ngẫu nhiên, đó là tất cả những gì uuidv4 cần có. Bạn có thể tạo 64 cho các URL ngắn hơn, chuyển nó trở lại một số trang web, lưu trữ trong không gian bộ nhớ ít hơn dưới dạng chuỗi, tạo bộ đệm có kích thước 4096 và đặt 256 uuids vào đó, lưu trữ trong db trình duyệt, v.v. hơn là có mọi thứ như một chuỗi mã hóa hex, chữ thường từ đầu.
Josh từ Qaribou

8

OK, sử dụng gói uuid , nó hỗ trợ cho các UUID phiên bản 1, 3, 4 và 5 :

yarn add uuid

và sau đó:

const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '45745c60-7b1a-11e8-9c9c-2d42b21b1a3e'

Bạn cũng có thể làm điều đó với các tùy chọn được chỉ định đầy đủ:

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'

Để biết thêm thông tin, hãy truy cập trang npm tại đây


6

Điều quan trọng là sử dụng mã được kiểm tra tốt, được duy trì bởi hơn 1 người đóng góp thay vì đánh cắp công cụ của riêng bạn cho việc này. Đây là một trong những nơi mà bạn có thể muốn sử dụng mã ổn định nhất so với phiên bản thông minh ngắn nhất có thể hoạt động trong trình duyệt X nhưng không tính đến các đặc điểm riêng của Y, điều này thường dẫn đến việc rất khó điều tra các lỗi so với các biểu hiện chỉ là ngẫu nhiên cho một số người dùng. Cá nhân tôi sử dụng uuid-js tại https://github.com/aurigadl/uuid-js cho phép bower để tôi có thể cập nhật dễ dàng.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.