วิธีสร้าง GUID / UUID


4178

ฉันกำลังพยายามสร้างตัวระบุที่ไม่ซ้ำกันทั่วโลกใน JavaScript ฉันไม่แน่ใจว่ามีรูทีนที่ใช้ได้ในเบราว์เซอร์ทั้งหมดอย่างไร "สุ่ม" และ seeded ตัวสร้างหมายเลขสุ่มในตัวเป็นต้น

GUID / UUID ควรมีอย่างน้อย 32 ตัวอักษรและควรอยู่ในช่วง ASCII เพื่อหลีกเลี่ยงปัญหาเมื่อผ่านไป


13
GUID ที่แสดงเป็นสตริงอย่างน้อย 36 ตัวและมีความยาวไม่เกิน 38 อักขระและตรงกับรูปแบบ ^ \ {? [a-zA-Z0-9] {36}? \} $ และด้วยเหตุนี้จึงเป็น ascii เสมอ
AnthonyWJones

2
David Bau ให้กำเนิดตัวเลขสุ่มที่ดีกว่ามากที่davidbau.com/archives/2010/01/30/ …ฉันเขียนแนวทางที่แตกต่างออกไปเล็กน้อยเพื่อสร้าง UUIDs ที่blogs.cozi.com/tech/2010/04/generating- uuids-in-javascript.html
George V. Reilly

แปลกที่ยังไม่มีใครพูดถึงเรื่องนี้ แต่เพื่อความสมบูรณ์มีนักสร้างguidมากมายเหลือเกินที่ npmฉันยินดีที่จะพนันส่วนใหญ่ทำงานในเบราว์เซอร์เช่นกัน
George Mauer

คำตอบ:


2339

UUIDs (Universally Unique IDentifier) ​​หรือที่รู้จักในชื่อ GUIDs (Global Unique IDentifier) ​​ตามRFC 4122เป็นตัวบ่งชี้ที่ออกแบบมาเพื่อรับประกันการรับประกันที่เป็นเอกลักษณ์

แม้ว่าจะเป็นไปได้ที่จะใช้ UUID ที่สอดคล้องกับ RFC ในไม่กี่บรรทัดของ JS (เช่นดูคำตอบของ @ broofaด้านล่าง) มีข้อผิดพลาดหลายประการ:

  • รูปแบบ id ไม่ถูกต้อง (UUID ต้องอยู่ในรูปแบบ " xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx" โดยที่ x คือหนึ่งใน [0-9, af] Mเป็นหนึ่งใน [1-5] และNคือ [8, 9, a หรือ b]
  • การใช้แหล่งที่มาของการสุ่มที่มีคุณภาพต่ำ (เช่นMath.random)

ดังนั้นนักพัฒนาที่เขียนรหัสสำหรับสภาพแวดล้อมการผลิตจะได้รับการสนับสนุนให้ใช้การดำเนินการที่เข้มงวดและบำรุงรักษาอย่างดีเช่นโมดูลuuid


186
ที่จริงแล้ว RFC อนุญาตสำหรับ UUID ที่สร้างขึ้นจากตัวเลขสุ่ม คุณเพียงแค่บิดสองสามบิตเพื่อระบุว่าเป็นเช่นนั้น ดูหัวข้อ 4.4 อัลกอริทึมสำหรับการสร้าง UUID จากตัวเลขสุ่มหรือสุ่มหลอกอย่างแท้จริง: rfc-archive.org/getrfc.php?rfc=4122
Jason DeFontes

สร้างทุกสิ่งในชุดข้อความนี้แล้วฉันสร้างรุ่นที่เร็วเป็นสองเท่าของตัวแปร "e7" ด้านล่าง crypto-strong และทำงานบนเบราว์เซอร์และโหนดหลักทั้งหมด มันใหญ่เกินไปที่จะรวมไว้ที่นี่ดังนั้นให้ค้นหาคำตอบใหม่ด้วยชื่อของฉันเมื่อวันที่ 17 พฤษภาคม 2020
Bennett Barouch

ตอนนี้โหนด uuid กลายเป็นuuid (หลังจากรวมกับโครงการหลัง)
Catweazle

4112

สำหรับโซลูชันที่สอดคล้องกับRFC4122เวอร์ชัน 4 โซลูชัน one-liner (ish) นี้มีขนาดกะทัดรัดที่สุดที่ฉันสามารถหาได้:

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()สำหรับระยะเวลาสั้น ๆ แต่Math.random()จะไม่รับประกันว่าจะเป็น RNG ที่มีคุณภาพสูง ดูรายละเอียดการเขียนที่ดีเยี่ยมของ Adam Hyland ใน Math.random ()เพื่อดูรายละเอียด สำหรับโซลูชันที่มีประสิทธิภาพยิ่งขึ้นให้ลองใช้โมดูล uuidซึ่งใช้ RNG API คุณภาพสูง

อัปเดต, 2015-08-25 : ในฐานะที่เป็นหมายเหตุข้างเคียง, สรุปสาระสำคัญนี้อธิบายวิธีการกำหนดจำนวน ID ที่สามารถสร้างก่อนที่จะถึงความน่าจะเป็นของการชน ตัวอย่างเช่นด้วย 3.26x10 15เวอร์ชัน 4 RFC4122 UUID คุณมีโอกาสชน 1 ใน 1 ล้าน

อัปเดต, 2017-08-25 : บทความที่ดีจากนักพัฒนา Chrome ที่พูดถึงสถานะของ Math.random ในเรื่องคุณภาพ PRNG ใน Chrome, Firefox และ Safari tl; dr - ปลายปี 2558 เป็น "ค่อนข้างดี" แต่ไม่ใช่คุณภาพการเข้ารหัส เพื่อแก้ไขปัญหาดังกล่าวต่อไปนี้เป็นโซลูชันที่ปรับปรุงด้านบนซึ่งใช้ ES6, cryptoAPI และตัวช่วยสร้าง 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());

Update, 2020-01-06 : มีข้อเสนอในการทำงานสำหรับuuidโมดูลมาตรฐานซึ่งเป็นส่วนหนึ่งของภาษา JS


30
ฉันโพสต์คำถามเกี่ยวกับการชนกันของstackoverflow.com/questions/6906916/…
Muxa

4
@marc - คุณภาพของ Math.random () เป็นปัญหา แต่หากไม่มีการวิเคราะห์อย่างละเอียดเกี่ยวกับการติดตั้งพื้นฐานซึ่งเกือบจะแตกต่างกันไปอย่างแน่นอนกับเบราว์เซอร์ x เราไม่สามารถรู้ถึงอัตราการชนที่แท้จริงได้ ดังนั้นเพื่อความเรียบง่ายฉันสมมติว่าเป็นแหล่งกำเนิดของการสุ่ม แต่ใช่ว่าอาจเป็นข้อสันนิษฐานที่อันตรายเนื่องจากประเด็นสำคัญของ muxa นอกจากนี้ยังเป็นสาเหตุใน node-uuid ( github.com/broofa/node-uuid ) ฉันชอบ API อื่น ๆ ที่รับประกันการเข้ารหัสแบบสุ่มที่มีคุณภาพการเข้ารหัสเหนือ Math.random () แม้ว่าประสิทธิภาพจะลดลงก็ตาม
broofa

144
แน่นอนคำตอบสำหรับคำถามของ @ Muxa คือ 'ไม่'? ไม่เคยปลอดภัยอย่างแท้จริงที่จะไว้วางใจสิ่งที่มาจากลูกค้า ฉันเดาว่าขึ้นอยู่กับว่าผู้ใช้ของคุณมีแนวโน้มที่จะสร้างคอนโซล JavaScript และเปลี่ยนตัวแปรด้วยตนเองเป็นสิ่งที่พวกเขาต้องการ หรือพวกเขาเพียงแค่โพสต์คุณกลับ ID ที่พวกเขาต้องการ นอกจากนี้ยังจะขึ้นอยู่กับว่าผู้ใช้เลือกรหัสของตนเองจะทำให้เกิดช่องโหว่หรือไม่ ไม่ว่าจะด้วยวิธีใดหากเป็นหมายเลขสุ่มที่กำลังจะเข้าสู่ตารางฉันอาจจะสร้างฝั่งเซิร์ฟเวอร์เพื่อให้ฉันรู้ว่าฉันสามารถควบคุมกระบวนการได้
Cam Jackson

36
@DrewNoakes - UUIDs ไม่เพียง แต่เป็นสตริงของ # สุ่มแบบสมบูรณ์ "4" เป็นรุ่น uuid (4 = "สุ่ม") เครื่องหมาย "y" ทำเครื่องหมายที่ตัวแปร uuid (การจัดวางฟิลด์โดยทั่วไป) จะต้องมีการฝัง ดูส่วน 4.1.1 และ 4.1.3 ของietf.org/rfc/rfc4122.txtสำหรับข้อมูลเพิ่มเติม
broofa

5
ทำไมแทนc== 'x' c === 'x'เพราะ jshint ล้มเหลว
Fizer Khan

810

ฉันชอบคำตอบที่สะอาดของ Broofaแต่โชคไม่ดีที่การใช้งานที่ไม่ดีMath.randomออกจากการปะทะกัน

ต่อไปนี้เป็นโซลูชันที่เข้ากันได้กับRFC4122เวอร์ชัน 4 ที่คล้ายกันซึ่งช่วยแก้ปัญหาดังกล่าวโดยการชดเชยเลขฐานสิบหกตัวแรกด้วยส่วนฐานสิบหกของเวลาประทับ ด้วยวิธีนี้แม้ว่าMath.randomจะอยู่ในเมล็ดเดียวกันลูกค้าทั้งสองจะต้องสร้าง UUID ด้วยจำนวนไมโครวินาทีที่แน่นอนตั้งแต่ pageload (ถ้ารองรับเวลาที่มีประสิทธิภาพสูง) และในมิลลิวินาทีเดียวกัน (หรือมากกว่า 10,000 ปี) เพื่อ รับ 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())


นี่คือซอที่จะทดสอบ


31
โปรดทราบว่าnew Date().getTime()จะไม่อัปเดตทุก ๆ มิลลิวินาที ฉันไม่แน่ใจว่าสิ่งนี้มีผลต่อการคาดคะเนอัลกอริทึมของคุณอย่างไร
devios1

84
ประสิทธิภาพการทำงานจะดียิ่งขึ้น ต่างจาก Date.now การประทับเวลาที่ส่งคืนโดยperformance.now()ไม่ จำกัด เพียงหนึ่งมิลลิวินาที แต่พวกเขาเป็นตัวแทนครั้งเป็นจำนวนจุดลอยตัวขึ้นไปด้วยความแม่นยำมิลลิ ซึ่งแตกต่างจาก Date.now ค่าที่ส่งคืนโดย performance.now () จะเพิ่มขึ้นในอัตราคงที่เสมอโดยไม่ขึ้นกับนาฬิการะบบซึ่งอาจถูกปรับด้วยตนเองหรือเบ้โดยซอฟต์แวร์เช่น Network Time Protocol
daniellmb

6
@daniellmb คุณอาจจะได้เชื่อมโยงกับ MDN หรืออื่นที่จะแสดงเอกสารจริงและไม่ polyfill หนึ่ง)
มาร์ติน

2
ฉันขอทราบการปัดเศษของการใช้งานได้d = Math.floor(d/16);อย่างไร
Praveen

2
@Praveen การดำเนินการนั้นเปลี่ยนการประทับเวลาหนึ่งฐานสิบหกหลักไปทางขวาและปล่อยส่วนที่เหลือ โดยมีวัตถุประสงค์คือเพื่อกำจัดเลขฐานสิบหกที่เราเพิ่งใช้ (ที่สำคัญน้อยที่สุด) และพร้อมสำหรับการทำซ้ำต่อไป
Briguy37

431

คำตอบของ broofa เรียบสวยแน่นอน - น่าประทับใจฉลาดจริง ๆ ... rfc4122 เป็นไปตามมาตรฐานอ่านได้ค่อนข้างกะทัดรัด ! น่ากลัว

แต่ถ้าคุณดูที่นิพจน์ทั่วไปการreplace()โทรกลับจำนวนมากtoString()และMath.random()การเรียกฟังก์ชัน (ซึ่งเขาใช้เพียง 4 บิตของผลลัพธ์และการสูญเสียที่เหลือ) คุณอาจเริ่มสงสัยเกี่ยวกับประสิทธิภาพ แท้จริง joelpt ตัดสินใจแม้จะโยนออก RFC สำหรับความเร็ว GUID 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ด้วยเลขฐานสิบหกแบบสุ่มใด ๆ ที่yมีข้อมูลแบบสุ่ม (ยกเว้นบังคับให้บิต 2 อันดับแรก10เป็นข้อมูลจำเพาะ RFC) และ regex ไม่ตรงกับ-หรือ4อักขระดังนั้นเขาจึงไม่ต้องจัดการกับพวกเขา ลื่นมาก ๆ

สิ่งแรกที่ต้องทราบคือการเรียกใช้ฟังก์ชันมีราคาแพงเช่นเดียวกับการแสดงผลปกติ (แม้ว่าเขาจะใช้เพียง 1 แต่ก็มี 32 การเรียกกลับหนึ่งรายการต่อการแข่งขันแต่ละครั้งและในการเรียกกลับ 32 ครั้งแต่ละครั้ง toString (16))

ขั้นตอนแรกสู่ประสิทธิภาพคือการกำจัด RegEx และฟังก์ชันการเรียกกลับและใช้การวนซ้ำอย่างง่ายแทน ซึ่งหมายความว่าเราต้องจัดการกับ-และ4ตัวละครในขณะที่ broofa ไม่ได้ นอกจากนี้โปรดทราบว่าเราสามารถใช้การจัดทำดัชนีสตริงอาเรย์เพื่อเก็บสถาปัตยกรรมเทมเพลตสตริงของเขา:

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และการใช้ลูป while (แทนการ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 แต่ก็ไม่ยากเกินไป จากนั้นเราต้องสร้างตารางการค้นหาที่ใหญ่ขึ้น (16x16 หรือ 256) เพื่อจัดเก็บ 0x00 - 0xff และเราสร้างเพียงครั้งเดียวนอกฟังก์ชั่น 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())

ฉันลองใช้ e6 () ที่ประมวลผลครั้งละ 16 บิตยังคงใช้ LUT 256- องค์ประกอบและมันแสดงให้เห็นถึงผลตอบแทนที่ลดลงของการปรับให้เหมาะสม แม้ว่ามันจะมีการวนซ้ำน้อยลง แต่ตรรกะภายในนั้นซับซ้อนโดยการประมวลผลที่เพิ่มขึ้นและมันทำงานบนเดสก์ท็อปเหมือนกันและเร็วขึ้นเพียง 10% บนมือถือ

เทคนิคการปรับให้เหมาะสมสุดท้ายที่จะนำไปใช้ - คลี่วง เนื่องจากเราวนซ้ำจำนวนครั้งเราจึงสามารถเขียนสิ่งนี้ออกมาได้ด้วยมือ ฉันลองสิ่งนี้ครั้งเดียวด้วยตัวแปรสุ่ม r เดียวที่ฉันยังคงทำการกำหนดใหม่และประสิทธิภาพของแท็งก์ แต่ด้วยตัวแปรสี่ตัวที่กำหนดข้อมูลแบบสุ่มไว้ล่วงหน้าจากนั้นใช้ตารางการค้นหาและใช้บิต 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())

ดัดแปลงแล้ว: http://jcward.com/UUID.js -UUID.generate()

สิ่งที่ตลกคือการสร้างข้อมูลแบบสุ่ม 16 ไบต์เป็นส่วนที่ง่าย เคล็ดลับทั้งหมดแสดงไว้ในรูปแบบ String ที่มีการปฏิบัติตาม RFC และสามารถทำได้อย่างแน่นหนาที่สุดด้วยข้อมูลแบบสุ่ม 16 ไบต์ตารางวนรอบและตารางค้นหา

ฉันหวังว่าตรรกะของฉันถูกต้อง - มันง่ายมากที่จะทำผิดพลาดในงานบิตที่น่าเบื่อแบบนี้ แต่ผลลัพธ์ดูดีสำหรับฉัน ฉันหวังว่าคุณจะสนุกไปกับการเพิ่มประสิทธิภาพของรหัส!

ได้รับคำแนะนำ:เป้าหมายหลักของฉันคือการแสดงและสอนกลยุทธ์การเพิ่มประสิทธิภาพที่มีศักยภาพ คำตอบอื่น ๆ ครอบคลุมหัวข้อที่สำคัญเช่นการชนกันและการสุ่มตัวเลขอย่างแท้จริงซึ่งเป็นสิ่งสำคัญสำหรับการสร้าง UUID ที่ดี


14
รหัสนี้ยังคงมีข้อผิดพลาดอยู่สองสามข้อ: Math.random()*0xFFFFFFFFบรรทัดควรใช้Math.random()*0x100000000สำหรับการสุ่มเต็มรูปแบบและ>>>0ควรใช้แทน|0การเก็บค่าที่ไม่ได้ลงชื่อ (แม้ว่าด้วยรหัสปัจจุบันฉันคิดว่ามันไม่เป็นไรแม้ว่าจะลงนามแล้วก็ตาม) ในที่สุดมันก็เป็นความคิดที่ดีมาก ๆ ที่วันนี้จะใช้window.crypto.getRandomValuesถ้ามีและถอยกลับไปที่ Math.random ก็ต่อเมื่อจำเป็นจริงๆ คณิตศาสตร์แบบสุ่มอาจมีเอนโทรปีน้อยกว่า 128 บิตซึ่งในกรณีนี้จะเสี่ยงต่อการชนมากกว่าที่จำเป็น
เดฟ

สร้างจากทุกสิ่งที่อยู่ในหัวข้อนี้ฉันได้สร้างสิ่งที่เร็วเป็นสองเท่าเป็น "e7" พกพาทุกสภาพแวดล้อมรวมถึงโหนดและอัปเกรดจาก Math.random () เป็นแบบสุ่มแรง crypto คุณอาจไม่คิดว่า uuid ต้องการความแข็งแกร่งของ crypto แต่นั่นหมายถึงโอกาสที่จะชนน้อยลงซึ่งเป็นจุดรวมของ uuid ใหญ่เกินกว่าที่จะใส่ความคิดเห็นได้ฉันได้โพสต์แยกต่างหาก
Bennett Barouch

164

นี่คือโค้ดบางส่วนตาม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;
}

4
คุณควรประกาศขนาดอาร์เรย์ไว้ล่วงหน้าแทนที่จะปรับขนาดแบบไดนามิกในขณะที่คุณสร้าง GUID var s = new Array(36);
MgSam

1
ฉันคิดว่ามีข้อบกพร่องเล็กน้อยในบรรทัดที่ตั้งค่าบิตบิต 6-7 ของ clock_seq_hi_and_reserved เป็น 01 เนื่องจาก s [19] เป็นอักขระ '0' .. 'f' และไม่ใช่ int 0x0..0xf, (s [19] & 0x3) | 0x8 จะไม่ถูกกระจายแบบสุ่ม - มันจะมีแนวโน้มที่จะผลิตมากขึ้น '9's และน้อยกว่า' b สิ่งนี้จะสร้างความแตกต่างถ้าคุณสนใจการกระจายแบบสุ่มด้วยเหตุผลบางอย่าง
John Velonis

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

หาก ID ของถูกสร้างขึ้นมากกว่า 1 มิลลิวินาทีนอกเหนือจากนั้นพวกเขาจะไม่ซ้ำกัน 100%

หาก ID สองรายการถูกสร้างขึ้นในช่วงเวลาที่สั้นลงและสมมติว่าวิธีการสุ่มเป็นแบบสุ่มอย่างแท้จริงนี่จะสร้าง ID ที่มีแนวโน้ม 99.99999999999999% ที่ไม่ซ้ำกันทั่วโลก (การชนกันใน 1 จาก 10 ^ 15)

คุณสามารถเพิ่มจำนวนนี้โดยการเพิ่มตัวเลขมากขึ้น แต่เพื่อสร้าง ID ที่ไม่ซ้ำกัน 100% คุณจะต้องใช้ตัวนับสากล

หากคุณต้องการความเข้ากันได้ของ RFC การจัดรูปแบบนี้จะผ่านเป็น GUID เวอร์ชัน 4 ที่ถูกต้อง:

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 ของคุณได้ที่นี่


4
นี่ไม่ใช่ UUID ใช่มั้ย
Marco Kerwitz

ไม่ได้ UUID / GUID คือหมายเลข 122 บิต (+ หกบิตสงวน) มันอาจรับประกันถึงความไม่เหมือนใครผ่านบริการตัวนับทั่วโลก แต่บ่อยครั้งที่มันสามารถถ่ายทอดตรงเวลาที่อยู่ MAC และการสุ่ม UUID ไม่สุ่ม! โพสต์ที่ฉันแนะนำที่นี่ไม่ได้ถูกบีบอัดอย่างเต็มที่ คุณสามารถบีบอัดเป็นจำนวนเต็ม 122 บิตเพิ่มบิตที่กำหนดไว้ล่วงหน้า 6 บิตและบิตสุ่มพิเศษ (ลบบิตตัวจับเวลาไม่กี่บิต) และคุณท้ายด้วย UUID / GUID ที่มีรูปแบบสมบูรณ์แบบที่คุณจะต้องแปลงเป็นเลขฐานสิบหก สำหรับฉันที่ไม่ได้เพิ่มอะไรเลยนอกจากการปฏิบัติตามความยาวของ ID จริงๆ
Simon Rigét

5
การถ่ายทอดที่อยู่ MAC เพื่อความเป็นเอกลักษณ์ในเครื่องเสมือนเป็นความคิดที่ไม่ดี!
Simon Rigét

1
ฉันทำอะไรเช่นนี้ แต่มีตัวละครนำและขีดคั่นบางอย่าง (เช่น[slug, date, random].join("_")เพื่อสร้างusr_1dcn27itd_hj6onj6phrมันทำให้ ID ยังเป็นสองเท่าเป็นฟิลด์ "สร้างที่"
Seph Reed

95

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()ฟังก์ชันส่งกลับตัวเลขทศนิยมระหว่าง 0 และ 1 กับ 16 หลักหลังจุดทศนิยมส่วน (ตัวอย่าง0.4363923368509859)
  • จากนั้นเราก็นำตัวเลขนี้มาแปลงเป็นสตริงที่มีฐาน 16 (จากตัวอย่างด้านบนเราจะได้ 0.6fb7687f)
    Math.random().toString(16).
  • จากนั้นเราจะตัด0.คำนำหน้า ( 0.6fb7687f=> 6fb7687f) และรับสตริงที่มีอักขระฐานสิบหกยาวแปดตัว
    (Math.random().toString(16).substr(2,8).
  • บางครั้งMath.random()ฟังก์ชันจะส่งคืนจำนวนที่สั้นกว่า (ตัวอย่าง0.4363) เนื่องจากค่าศูนย์ที่ท้าย (จากตัวอย่างด้านบนจำนวนที่เป็นจริง0.4363000000000000) นั่นเป็นเหตุผลที่ฉันต่อท้ายสตริงนี้"000000000"(สตริงที่มีเก้าศูนย์) แล้วตัดมันออกมาพร้อมกับsubstr()ฟังก์ชั่นเพื่อทำให้มันเป็นตัวละครที่เก้า (การเติมศูนย์ไปทางขวา)
  • เหตุผลในการเพิ่มศูนย์เก้าตัวนั้นเป็นเพราะสถานการณ์กรณีที่แย่กว่านั้นคือเมื่อMath.random()ฟังก์ชันจะส่งกลับค่า 0 หรือ 1 (ความน่าจะเป็น 1/10 ^ 16 สำหรับแต่ละสถานการณ์) นั่นเป็นเหตุผลที่เราจำเป็นต้องเพิ่มศูนย์เก้า ( "0"+"000000000"หรือ"1"+"000000000") แล้วตัดออกจากดัชนีที่สอง (ตัวละครที่ 3) ที่มีความยาวแปดตัวอักษร สำหรับส่วนที่เหลือของกรณีการเพิ่มศูนย์จะไม่เป็นอันตรายต่อผลเพราะมันถูกตัดออกไป
    Math.random().toString(16)+"000000000").substr(2,8).

การชุมนุม:

  • GUID XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXXที่อยู่ในรูปแบบดังต่อไปนี้
  • ผมแบ่ง GUID เป็น 4 ชิ้นแต่ละชิ้นแบ่งออกเป็น 2 ประเภท (หรือรูปแบบ) และXXXXXXXX-XXXX-XXXX
  • ตอนนี้ผมกำลังสร้าง GUID โดยใช้ทั้ง 2 ประเภทในการประกอบ GUID ที่มีการเรียกร้อง 4 XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXXชิ้นดังนี้
  • แตกต่างระหว่างทั้งสองประเภทฉันเพิ่มพารามิเตอร์ธงไปยังฟังก์ชันคู่ผู้สร้าง_p8(s)ที่sพารามิเตอร์บอกฟังก์ชั่นไม่ว่าจะเป็นการเพิ่มขีดกลางหรือไม่
  • ในที่สุดเราก็สร้าง GUID ด้วยการผูกมัดต่อไปนี้: _p8() + _p8(true) + _p8(true) + _p8()และคืนมัน

ลิงก์ไปที่โพสต์นี้ในบล็อกของฉัน

สนุก! :-)


13
การใช้งานนี้ไม่ถูกต้อง อักขระบางตัวของ GUID ต้องการการดูแลเป็นพิเศษ (เช่นตัวเลข 13 หลักต้องเป็นหมายเลข 4)
JLRishe

67

นี่คือการรวมกันของคำตอบที่ได้รับคะแนนสูงสุดพร้อมวิธีแก้ไขสำหรับการชนของ 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หากคุณต้องการทดสอบ


3
ทราบว่ารุ่นแรกหนึ่ง `window.crypto.getRandomValues , 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มันอัตราผลตอบแทน
humanityANDpeace

66

นี่คือการใช้งานที่ไม่เข้ากัน แต่มีประสิทธิภาพมากในการสร้างตัวบ่งชี้ที่ไม่เหมือนใครเช่น ASCII ที่ปลอดภัย

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

สร้างอักขระ 26 [a-z0-9] ซึ่งให้ UID ที่สั้นกว่าและไม่ซ้ำกันกว่า GUID ที่เข้ากันได้กับ RFC สามารถเพิ่มขีดกลางได้เล็กน้อยหากมนุษย์สามารถอ่านได้

นี่คือตัวอย่างการใช้งานและการกำหนดเวลาสำหรับฟังก์ชั่นนี้และคำตอบอื่น ๆ ของคำถามนี้ เวลาถูกดำเนินการภายใต้ Chrome m25, 10 ล้านรอบซ้ำ

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

62

นี่คือวิธีการแก้ปัญหาลงวันที่ 9 ตุลาคม 2011 จากความคิดเห็นโดยผู้ใช้jedที่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)}

สิ่งนี้บรรลุเป้าหมายเดียวกันกับคำตอบที่ได้รับคะแนนสูงสุดในปัจจุบันแต่ใช้เวลาน้อยกว่า 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
      )
}

52

จากบล็อกทางเทคนิคของ 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;
}

มีวิธีอื่น ๆ ที่เกี่ยวข้องกับการใช้ตัวควบคุม ActiveX แต่อยู่ห่างจากสิ่งเหล่านี้!

แก้ไข: ฉันคิดว่ามันคุ้มค่าที่ชี้ให้เห็นว่าไม่มีตัวสร้าง GUID สามารถรับประกันคีย์ที่ไม่ซ้ำกัน (ตรวจสอบบทความวิกิพีเดีย ) มีโอกาสชนกันอยู่เสมอ GUID มอบกุญแจขนาดใหญ่ในจักรวาลเพื่อลดการเปลี่ยนแปลงของการชนจนเกือบเป็นศูนย์


8
โปรดทราบว่านี่ไม่ใช่ GUID ในแง่เทคนิคเนื่องจากไม่มีสิ่งใดรับประกันความเป็นเอกลักษณ์ อาจมีหรือไม่มีความสำคัญขึ้นอยู่กับแอปพลิเคชันของคุณ
Stephen Deken

2
บันทึกย่อเกี่ยวกับประสิทธิภาพ โซลูชันนี้สร้างผลรวม 36 สายเพื่อให้ได้ผลลัพธ์เดียว หากประสิทธิภาพมีความสำคัญให้พิจารณาสร้างอาร์เรย์และเข้าร่วมตามที่แนะนำโดย: tinyurl.com/y37xtx การวิจัยเพิ่มเติมบ่งชี้ว่ามันอาจไม่สำคัญดังนั้น YMMV: tinyurl.com/3l7945
Brandon DuRette

2
เกี่ยวกับความไม่เหมือนใครมันก็คุ้มค่าที่จะสังเกตว่ารุ่น 1,3 และ 5 UUID นั้นถูกกำหนดไว้ในแบบที่ 4 ไม่ใช่ หากอินพุตไปยังตัวสร้าง uuid เหล่านี้ - node id ใน v1, เนมสเปซและชื่อใน v3 และ v5 - ไม่ซ้ำกัน (ตามที่ควรจะเป็น) ดังนั้น UUID ที่เป็นผลลัพธ์จะไม่ซ้ำกัน ในทางทฤษฎีแล้ว
broofa

41

คุณสามารถใช้ node-uuid ( https://github.com/kelektiv/node-uuid )

ง่าย, รวดเร็วรุ่นของRFC4122 UUIDS

คุณสมบัติ:

  • สร้าง RFC4122 เวอร์ชัน 1 หรือ UUID เวอร์ชัน 4
  • รันใน node.js และเบราว์เซอร์
  • การสร้าง # แบบสุ่มที่แข็งแกร่งในการเข้ารหัสบนแพลตฟอร์มที่รองรับ
  • รอยเท้าขนาดเล็ก (ต้องการอะไรที่เล็กกว่านี้หรือลองดูนี่สิ! )

ติดตั้งโดยใช้ NPM:

npm install uuid

หรือใช้ uuid ผ่านเบราว์เซอร์:

ดาวน์โหลดไฟล์ Raw (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js ดาวน์โหลดไฟล์ Raw (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();

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

แก้ไข:

กลับมายังโครงการของฉันที่ใช้ฟังก์ชันนี้และไม่ชอบคำฟุ่มเฟื่อย - แต่ต้องการการสุ่มที่เหมาะสม

เวอร์ชันที่อิงตามคำตอบของ Briguy37 และตัวดำเนินการระดับบิตบางอย่างเพื่อแยกหน้าต่างขนาดเท่าทันออกจากบัฟเฟอร์

ควรเป็นไปตามสคีมา RFC Type 4 (สุ่ม) เนื่องจากฉันมีปัญหาครั้งล่าสุดในการแยก uuids ที่ไม่สอดคล้องกับ UUID ของ Java


31

โมดูล JavaScript อย่างง่ายเป็นการรวมกันของคำตอบที่ดีที่สุดในหัวข้อนี้

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"


1
อะไรคือสิ่งที่รบกวนเกี่ยวกับทุกคำตอบก็คือว่ามันดูเหมือนว่าokสำหรับ JavaScript เพื่อเก็บเป็นGUID stringคำตอบของคุณที่โหม่งน้อยมากUint16Arrayการเก็บรักษามีประสิทธิภาพมากขึ้นโดยใช้ toStringฟังก์ชั่นควรจะใช้แทน binary ใน JavaScriptobject
เซบาสเตียน

UUID นี้สร้างขึ้นโดยรหัสนี้อาจเป็นไปตามมาตรฐาน RFC (_guid) หรืออ่อนแอ แต่ไม่ใช่ RFC (_cryptoGuid) อดีตใช้ Math.random () ซึ่งขณะนี้เป็นที่รู้จักกันว่า RNG ไม่ดี หลังมีความล้มเหลวในการตั้งค่ารุ่นและเขตข้อมูลตัวแปร
broofa

@broofa - คุณอยากจะแนะนำอะไรให้แข็งแกร่งและสอดคล้องกับ RFC? และทำไม _cryptoGuid จึงไม่สอดคล้องกับ RFC
Matt

@Matt _cryptoGuid () ตั้งค่าทั้งหมด 128 บิตแบบสุ่มหมายความว่ามันไม่ได้ตั้งค่ารุ่นและเขตข้อมูลตัวแปรตามที่อธิบายไว้ใน RFC ดูการติดตั้ง uuidv4 () อื่น ๆ ของฉันที่ใช้ crypto.getRandomValues ​​() ในคำตอบที่ได้รับคะแนนสูงสุดของฉันสำหรับการใช้งานที่สอดคล้องกับมาตรฐาน +
broofa

29

สิ่งนี้สร้าง UUID รุ่น 4 (สร้างจากตัวเลขสุ่มหลอก):

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

28

นี่มีคำตอบมากมายอยู่แล้ว แต่น่าเสียดายที่ไม่มีการสุ่ม "จริง" ในกลุ่ม รุ่นด้านล่างเป็นการปรับคำตอบของ broofa แต่ปรับปรุงเพื่อรวมฟังก์ชั่นการสุ่ม "ของจริง" ที่ใช้ไลบรารี crypto ที่มีอยู่และฟังก์ชัน 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);
  });
};

27

โครงการ JavaScript บน GitHub - https://github.com/LiosK/UUID.js

UUID.js ตัวสร้าง UUID ที่สอดคล้องกับ RFC สำหรับ JavaScript

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

คุณสมบัติสร้าง UUID ที่สอดคล้องกับ RFC 4122

เวอร์ชัน 4 UUIDs (UUID จากตัวเลขสุ่ม) และรุ่น 1 UUIDs (UUID ที่อิงตามเวลา) พร้อมใช้งาน

วัตถุ UUID ช่วยให้สามารถเข้าถึง UUID ได้หลากหลายรวมถึงการเข้าถึงฟิลด์ UUID

ความละเอียดการประทับเวลาต่ำของ JavaScript ถูกชดเชยด้วยตัวเลขสุ่ม


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

ฉันต้องการที่จะเข้าใจคำตอบของ 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);
        }
    );
};

ขอบคุณสำหรับคำอธิบายรายละเอียด! แทะเละโดยเฉพาะระหว่าง 8 และ 11 พร้อมคำอธิบายที่เทียบเท่าจะเป็นประโยชน์มาก
Egor Litvinchuk

15

ปรับตัวเอง UUID / เครื่องกำเนิดไฟฟ้า GUID ของฉันกับความพิเศษบางอย่างที่นี่

ฉันใช้ตัวสร้างตัวเลขสุ่มKybos ต่อไปนี้เพื่อให้ได้เสียงที่เข้ารหัสลับมากกว่าเดิม

ด้านล่างเป็นสคริปต์ของฉันด้วยวิธี Mash และ Kybos จาก baagoe.com ยกเว้น

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

สำหรับผู้ที่ต้องการโซลูชันที่เข้ากันได้กับ rfc4122 เวอร์ชัน 4 พร้อมข้อควรพิจารณาด้านความเร็ว

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

ฟังก์ชั่นด้านบนควรมีความสมดุลที่เหมาะสมระหว่างความเร็วและการสุ่ม


13

ตัวอย่าง 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

วิธีที่ดีกว่า:

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}

11

ฉันรู้ว่ามันเป็นคำถามเก่า เพียงเพื่อความสมบูรณ์ถ้าสภาพแวดล้อมของคุณคือ SharePoint มีฟังก์ชันยูทิลิตี้ที่เรียกว่าSP.Guid.newGuid( ลิงก์ msdn ) ซึ่งสร้าง guid ใหม่ ฟังก์ชันนี้อยู่ในไฟล์ 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;
};

11

อันนี้ขึ้นอยู่กับวันที่และเพิ่มคำต่อท้ายแบบสุ่มเพื่อ "รับรอง" เอกลักษณ์ ทำงานได้ดีสำหรับตัวระบุ 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;
        };

11

รหัสธรรมดาที่ใช้crypto.getRandomValues(a)กับเบราว์เซอร์ที่รองรับ (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome) หลีกเลี่ยงการใช้Math.random()เพราะอาจทำให้เกิดการชน (เช่นการชน 20 ครั้งสำหรับ 4000 uuids ที่สร้างขึ้นในสถานการณ์จริงโดย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);
}

หมายเหตุ:

  • ปรับให้เหมาะสมสำหรับการอ่านรหัสไม่ใช่ความเร็วดังนั้นเหมาะสำหรับพูดไม่กี่ร้อย uuid ต่อวินาที สร้างประมาณ 10,000 uuid () ต่อวินาทีใน Chromium บนแล็ปท็อปของฉันโดยใช้http://jsbin.com/fuwigo/1เพื่อวัดประสิทธิภาพ
  • ใช้ 8 สำหรับ "y" เท่านั้นเพราะจะทำให้การอ่านรหัสง่ายขึ้น (y ได้รับอนุญาตให้เป็น 8, 9, A หรือ B)

11

หากคุณต้องการสตริง 128 บิตแบบสุ่มในรูปแบบที่ไม่มีคุณสามารถใช้:

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

2350143528-4164020887-938913176-2513998651ซึ่งจะกลับมาบางอย่างเช่น


BTW ทำไมมันสร้างเพียงตัวเลขและไม่ใช่ตัวอักษรเช่นกัน? ปลอดภัยน้อยกว่า
vsync

1
คุณสามารถเพิ่มตัวอักษร (ตัวอักษร) ดังนี้:Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
magikMaker

11

ตัวแปรอื่นที่อ่านได้ง่ายขึ้นเพียงสองการกลายพันธุ์

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

นักพัฒนา js ส่วนใหญ่นั้นเป็นนักพัฒนาเว็บและเราไม่เข้าใจว่าตัวดำเนินการ bitwise ทำอะไรเพราะเราไม่ได้ใช้พวกเขาเกือบทุกครั้งที่เราพัฒนา จริงๆแล้วฉันไม่เคยต้องการสิ่งใดเลยและฉันเป็น js dev ตั้งแต่ '97 ดังนั้นโค้ดตัวอย่างของคุณยังไม่สามารถอ่านได้โดยเฉลี่ยสำหรับนักพัฒนาเว็บโดยทั่วไปที่จะอ่าน ไม่ต้องพูดถึงว่าคุณยังคงใช้ชื่อตัวแปรตัวอักษรเดียวซึ่งทำให้มันเป็นความลับมากยิ่งขึ้น อาจอ่าน Clean Code ซึ่งอาจช่วยได้: amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
inf3rno

@ inf3rno ไม่ทุบตีเขาโซลูชั่นที่นำเสนอทั้งหมดในชุดข้อความนี้เป็นความลับ แต่พวกเขาตอบถูกต้องเมื่อพิจารณาคำถามก็คือต้องมีซับไลน์หนึ่งบรรทัด นั่นคือสิ่งที่หนึ่ง liners เป็นความลับ พวกเขาไม่สามารถที่จะอ่านได้โดยผู้พัฒนาโดยเฉลี่ย แต่พวกเขาบันทึกอสังหาริมทรัพย์บนหน้าจอที่ความคิดเห็นก่อนหน้านี้ง่ายจะทำ และเป็นผลให้จบลงด้วยการอ่านได้มากกว่านั้นถ้ามันอยู่ใน "รหัสที่อ่านได้" แทน
tatsu

สุ่ม! = ไม่ซ้ำกัน
user1529413

@ user1529413 ใช่ เอกลักษณ์ต้องมีดัชนี
เซฟ

นี่คือคำตอบที่ฉันโปรดปรานเพราะมันสร้าง UUID เป็นค่า 16- ไบต์ (128 บิต) และไม่ใช่แบบฟอร์มที่ดีต่อการอ่าน มันง่ายมากที่จะวางสิ่งที่เป็นสตริงและเพียงแค่ตั้งค่าบิตที่ถูกต้องของบิตแบบสุ่ม 128 บิตซึ่งเป็น uuidv4 ทั้งหมดที่จำเป็นต้องมี คุณสามารถ base64 สำหรับ URL ที่สั้นกว่าส่งกลับไปยัง webassembly บางส่วนเก็บไว้ในพื้นที่หน่วยความจำน้อยกว่าเป็นสตริงทำให้เป็นบัฟเฟอร์ขนาด 4096 และใส่ 256 uuids เก็บไว้ในเบราว์เซอร์ db เป็นต้นดีกว่ามาก กว่าจะมีทุกอย่างที่เป็นสตริงสตริงที่เข้ารหัส hex แบบตัวพิมพ์เล็กตั้งแต่ต้น
Josh จาก Qaribou

8

ตกลงโดยใช้แพ็คเกจuuidรองรับเวอร์ชัน 1, 3, 4 และ 5 UUIDs :

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'

สำหรับข้อมูลเพิ่มเติมโปรดเยี่ยมชมหน้า npm ที่นี่


6

เป็นสิ่งสำคัญที่จะต้องใช้รหัสที่ผ่านการทดสอบอย่างดีซึ่งดูแลโดยผู้มีส่วนร่วมมากกว่า 1 คนแทนที่จะทำสิ่งที่คุณทำเอง นี่เป็นหนึ่งในสถานที่ที่คุณอาจต้องการที่จะต้องการรหัสที่เสถียรที่สุดกว่ารุ่นที่ฉลาดที่สุดที่สั้นที่สุดที่ทำงานใน X เบราว์เซอร์ แต่ไม่คำนึงถึงความเป็นไปได้ที่บัญชีของ Y ซึ่งมักจะนำไปสู่ สำหรับผู้ใช้บางคน ส่วนตัวฉันใช้ uuid-js ที่https://github.com/aurigadl/uuid-jsซึ่งเปิดใช้งาน bower เพื่อให้ฉันสามารถอัปเดตได้อย่างง่ายดาย

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.