सवाल जावास्क्रिप्ट में GUID / UUID बनाएँ?


मैं जावास्क्रिप्ट में वैश्विक रूप से अद्वितीय पहचानकर्ता बनाने की कोशिश कर रहा हूं। मुझे यकीन नहीं है कि सभी ब्राउज़रों पर कौन सी दिनचर्या उपलब्ध है, कैसे "यादृच्छिक" और अंतर्निहित यादृच्छिक संख्या जनरेटर बीजित है, आदि ..

GUID / UUID कम से कम 32 वर्ण होने चाहिए और उन्हें आस पास होने पर परेशानी से बचने के लिए ASCII रेंज में रहना चाहिए।


3219


मूल


GUIDs जब तारों के रूप में दोबारा तैयार किया जाता है तो कम से कम 36 होते हैं और लंबाई में 38 वर्ण से अधिक नहीं होते हैं और पैटर्न ^ \ {? [A-zA-Z0-9] {36}? \} $ से मेल खाते हैं और इसलिए हमेशा ascii होते हैं। - AnthonyWJones
डेविड बाउ एक बेहतर, बीज योग्य यादृच्छिक संख्या जनरेटर प्रदान करता है davidbau.com/archives/2010/01/30/... मैंने यूयूआईडी उत्पन्न करने के लिए थोड़ा अलग दृष्टिकोण लिखा है blogs.cozi.com/tech/2010/04/generating-uuids-in-javascript.html - George V. Reilly
jsben.ch/#/Lbxoe - नीचे से विभिन्न कार्यों के साथ एक बेंचमार्क - EscapeNetscape
UUID यादृच्छिक अच्छा पीआरएनजी का उपयोग करता है और बहुत तेज़ है। - jchook
देर से (बहुत देर हो चुकी है!) पार्टी में लेकिन @ एंथनी WJones को आपके regex को नहीं पढ़ना चाहिए: ^ \ {? [A-fA-F0-9] {36}? \} $ - noonand


जवाब:


इस पर कुछ प्रयास किए गए हैं। सवाल यह है: क्या आप वास्तविक GUID, या केवल यादृच्छिक संख्या चाहते हैं देखना GUID की तरह? यादृच्छिक संख्या उत्पन्न करना काफी आसान है।

function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

हालांकि, ध्यान दें कि ऐसे मूल्य असली GUID नहीं हैं

जावास्क्रिप्ट में वास्तविक GUID उत्पन्न करने का कोई तरीका नहीं है, क्योंकि वे स्थानीय कंप्यूटर के गुणों पर निर्भर करते हैं जो ब्राउज़र प्रकट नहीं करते हैं। आपको ओएस-विशिष्ट सेवाओं जैसे ActiveX का उपयोग करने की आवश्यकता होगी: http://p2p.wrox.com/topicindex/20339.htm

संपादित करें: सही नहीं - आरएफसी 4122 यादृच्छिक ("संस्करण 4") GUIDs की अनुमति देता है। विशिष्टताओं के लिए अन्य उत्तरों देखें।

ध्यान दें: प्रदान किया गया कोड स्निपेट RFC4122 का पालन नहीं करता है जिसके लिए संस्करण (4) उत्पन्न आउटपुट स्ट्रिंग में एकीकृत किया जाना है। इस उत्तर का प्रयोग न करें अगर आपको अनुपालन GUID की आवश्यकता है।

उपयोग:

var uuid = guid();

डेमो:

function guid() {
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
    s4() + '-' + s4() + s4() + s4();
}

function s4() {
  return Math.floor((1 + Math.random()) * 0x10000)
    .toString(16)
    .substring(1);
}

document.getElementById('jsGenId').addEventListener('click', function() {
  document.getElementById('jsIdResult').value = guid();
})
input { font-family: monospace; }
<button id="jsGenId" type="button">Generate GUID</button>
<br>
<input id="jsIdResult" type="text" placeholder="Results will be placed here..." readonly size="40"/>


1904



दरअसल, आरएफसी यूयूआईडी के लिए अनुमति देता है जो यादृच्छिक संख्या से बनाए जाते हैं। आपको बस इस तरह की पहचान करने के लिए कुछ बिट्स को झुकाव करना होगा। धारा 4.4 देखें। वास्तव में यादृच्छिक या छद्म-यादृच्छिक संख्या से यूयूआईडी बनाने के लिए एल्गोरिदम: rfc-archive.org/getrfc.php?rfc=4122 - Jason DeFontes
क्या कोई मुझे इस कोड को समझा सकता है? ऐसा लगता है कि एस 4 फ़ंक्शन 0x10000 और 0x20000 के बीच एक यादृच्छिक हेक्स संख्या प्राप्त करने का प्रयास करता है, फिर अंतिम 4 अंकों को आउटपुट करता है। लेकिन क्यों bitwise या 0 के साथ? क्या यह एक नोप नहीं होना चाहिए? इसके अलावा, 0x10000 से 0x20000 केवल 0 हैक से निपटने से बचने के लिए एक हैक है? - Cory
क्रोम में यह कोड हमेशा सही आकार GUID उत्पन्न नहीं करता है। लंबाई 35 से 36 के बीच बदलती है - cdeutsch
एक स्पष्ट रूप से गलत जवाब कैसे इतने सारे अपवर्तनीय हो सकता है? यहां तक ​​कि कोड गलत है, क्योंकि सही स्थिति में 4 नहीं है। en.wikipedia.org/wiki/Globally_unique_identifier - Dennis Krøger
यह जवाब संशोधन 5 में तोड़ा गया था जब "1 + ...." और "substring (1)" हटा दिए गए थे। उन बिट्स ने लगातार लंबाई की गारंटी दी। - Segfault


एक के लिए RFC4122 संस्करण 4 अनुपालन समाधान, यह एक-लाइनर (आईएसएच) समाधान सबसे कॉम्पैक्ट है जिसके साथ मैं आ सकता हूं .:

function uuidv4() {
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
    var r = Math.random() * 16 | 0, v = c == 'x' ? r : (r & 0x3 | 0x8);
    return v.toString(16);
  });
}

console.log(uuidv4())

अपडेट, 2015-06-02: ध्यान रखें कि यूयूआईडी विशिष्टता अंतर्निहित यादृच्छिक संख्या जेनरेटर (आरएनजी) पर भारी निर्भर करती है। उपरोक्त समाधान का उपयोग करता है Math.random() हालांकि, संक्षिप्तता के लिए Math.random() है नहीं एक उच्च गुणवत्ता वाले आरएनजी होने की गारंटी है। एडम हाइलैंड देखें Math.random पर उत्कृष्ट लेखन () ब्योरा हेतु। एक और मजबूत समाधान के लिए, कुछ इस तरह पर विचार करें यूयूआईडी मॉड्यूल[अस्वीकरण: मैं लेखक हूं], जो उपलब्ध उच्च गुणवत्ता वाले आरएनजी एपीआई का उपयोग करता है।

अद्यतन, 2015-08-26: एक साइड नोट के रूप में, यह सार यह बताता है कि टक्कर की एक निश्चित संभावना तक पहुंचने से पहले कितनी आईडी उत्पन्न की जा सकती है। उदाहरण के लिए, 3.26x10 के साथ15 संस्करण 4 आरएफसी 4122 यूयूआईडीएस आपके पास टकराव का 1 मिलियन लाख मौका है।

अद्यतन, 2017-06-28: ए क्रोम डेवलपर्स से अच्छा लेख क्रोम, फ़ायरफ़ॉक्स और सफारी में Math.random PRNG गुणवत्ता की स्थिति पर चर्चा। टीएल; डॉ - 2015 के अंत तक यह "बहुत अच्छा" है, लेकिन क्रिप्टोग्राफिक गुणवत्ता नहीं है। उस समस्या को हल करने के लिए, ऊपर दिए गए समाधान का एक अद्यतन संस्करण है जो ES6 का उपयोग करता है crypto एपीआई, और जेएस जादूगर का थोड़ा सा मैं क्रेडिट नहीं ले सकता:

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


3150



क्या क्लाइंट पर अद्वितीय आईडी उत्पन्न करने के लिए इस कोड का उपयोग करना सुरक्षित है, और उसके बाद उन आईडी को सर्वर पर ऑब्जेक्ट्स को सहेजने के लिए प्राथमिक कुंजी के रूप में उपयोग करें? - Muxa
... (cont'd) इस फ़ंक्शन टकराव द्वारा उत्पन्न दो आईडी की बाधाएं सचमुच खगोलीय रूप से छोटी हैं। आईडी के 128 बिट्स में से 6 यादृच्छिक रूप से जेनरेट किए गए हैं, जिसका मतलब है कि किसी भी दो आईडी के लिए, 2 ^^ 122 (या 5.3x10 ^^ 36) में 1 में से एक मौका होगा। - broofa
मैंने टक्कर के बारे में एक सवाल पोस्ट किया stackoverflow.com/questions/6906916/... - Muxa
निश्चित रूप से @ मुक्सा के सवाल का जवाब 'नहीं' है? क्लाइंट से आने वाली किसी चीज़ पर भरोसा करना कभी भी सुरक्षित नहीं होता है। मुझे लगता है कि यह इस बात पर निर्भर करता है कि आपके उपयोगकर्ता जावास्क्रिप्ट कंसोल कैसे ला सकते हैं और वेरिएबल को मैन्युअल रूप से बदल सकते हैं ताकि वे चाहते हैं। या वे सिर्फ उस आईडी को वापस पोस्ट कर सकते हैं जो वे चाहते हैं। यह इस बात पर भी निर्भर करेगा कि क्या उपयोगकर्ता अपनी आईडी चुन रहा है यानी कमजोरियों का कारण बन रहा है। किसी भी तरह से, यदि यह एक यादृच्छिक संख्या आईडी है जो किसी तालिका में जा रहा है, तो शायद मैं इसे सर्वर-साइड उत्पन्न कर रहा हूं, ताकि मुझे पता चले कि मेरे पास प्रक्रिया पर नियंत्रण है। - Cam Jackson
@DrewNoakes - यूयूआईडी पूरी तरह से यादृच्छिक # की एक स्ट्रिंग नहीं है। "4" यूयूआईडी संस्करण (4 = "यादृच्छिक") है। "वाई" अंक जहां यूयूआईडी संस्करण (फ़ील्ड लेआउट, मूल रूप से) को एम्बेड करने की आवश्यकता है। खंड 4.1.1 और 4.1.3 देखें ietf.org/rfc/rfc4122.txt अधिक जानकारी के लिए। - broofa


मुझे वास्तव में कितना साफ पसंद है ब्रूफा का जवाब है, लेकिन यह दुर्भाग्यपूर्ण है कि खराब कार्यान्वयन Math.random टक्कर के लिए मौका छोड़ दो।

यहाँ एक समान है RFC4122 संस्करण 4 अनुपालन समाधान जो टाइमस्टैम्प के हेक्स हिस्से द्वारा पहले 13 हेक्स संख्याओं को ऑफ़सेट करके उस समस्या को हल करता है। इस तरह, भले ही Math.randomएक ही बीज पर है, दोनों ग्राहकों को एक ही यूयूआईडी प्राप्त करने के लिए सटीक उसी मिलीसेकंड (या 10,000+ साल बाद) में यूयूआईडी उत्पन्न करना होगा:

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();
    if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
        d += performance.now(); //use high-precision timer if available
    }
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = (d + Math.random() * 16) % 16 | 0;
        d = Math.floor(d / 16);
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}


परीक्षण करने के लिए यहाँ एक पहेली है।


672



ध्यान में रखना, new Date().getTime() हर मिलीसेकंद अद्यतन नहीं है। मुझे यकीन नहीं है कि यह आपके एल्गोरिदम की अपेक्षित यादृच्छिकता को कैसे प्रभावित करता है। - devios1
मुझे लगता है कि यह सबसे अच्छा जवाब है क्योंकि यह इसकी पीढ़ी की तारीख का उपयोग करता है। हालांकि यदि आपके पास एक आधुनिक ब्राउज़र स्टैक है तो मैं अनुशंसा करता हूं Date.now() सेवा मेरे new Date().getTime() - Fresheyeball
performance.now बेहतर होगा। तिथि के विपरीत। अब, टाइमस्टैम्प द्वारा लौटाया गया performance.now() एक मिलीसेकंद संकल्प तक सीमित नहीं है। इसके बजाए, वे समय के साथ फ्लोटिंग-पॉइंट नंबर के रूप में प्रतिनिधित्व करते हैं microsecond परिशुद्धता। Date.now के विपरीत, प्रदर्शन द्वारा लौटाए गए मान .now () हमेशा एक स्थिर दर पर वृद्धि, सिस्टम घड़ी से स्वतंत्र है जिसे मैन्युअल रूप से समायोजित किया जा सकता है या नेटवर्क टाइम प्रोटोकॉल जैसे सॉफ़्टवेयर द्वारा छोड़ा जा सकता है। - daniellmb
@daniellmb आपको शायद वास्तविक दस्तावेज दिखाने के लिए एमडीएन या किसी अन्य से लिंक करना चाहिए था, न कि पॉलीफिल;) - Martin
एफवाईआई, साइट फूटर के अनुसार, साइट पर सभी उपयोगकर्ता योगदान सीसी द्वारा 3.0 लाइसेंस के तहत उपलब्ध हैं। - Xiong Chiamiov


ब्रोफा का जवाब बहुत चालाक है, वास्तव में - प्रभावशाली चालाक, वास्तव में ... आरएफसी 4122 अनुपालन, कुछ हद तक पठनीय, और कॉम्पैक्ट। बहुत बढ़िया!

लेकिन अगर आप उस नियमित अभिव्यक्ति को देख रहे हैं, तो बहुत से लोग replace() कॉलबैक, toString()'रेत Math.random() फ़ंक्शन कॉल (जहां वह केवल परिणाम के 4 बिट्स का उपयोग कर रहा है और बाकी को बर्बाद कर रहा है), आप प्रदर्शन के बारे में आश्चर्यचकित हो सकते हैं। दरअसल, जोएलपेट ने जेनेरिक GUID गति के लिए आरएफसी को टॉस करने का भी फैसला किया generateQuickGUID

लेकिन, क्या हम गति प्राप्त कर सकते हैं तथा आरएफसी अनुपालन? मैं हां कहूंगा!  क्या हम पठनीयता को बनाए रख सकते हैं? खैर ... वास्तव में नहीं, लेकिन यदि आप साथ चलते हैं तो यह आसान है।

लेकिन सबसे पहले, मेरे परिणाम, ब्रोफा की तुलना में, guid (स्वीकार्य उत्तर), और गैर-आरएफसी-अनुपालन 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। और मैं अभी भी आरएफसी 4122 अनुपालन कर रहा हूँ।

कैसे दिलचस्पी है? मैंने पूरा स्रोत रखा है http://jsfiddle.net/jcward/7hyaC/3/ और इसपर http://jsperf.com/uuid-generator-opt/4

स्पष्टीकरण के लिए, आइए ब्रोफा के कोड से शुरू करें:

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

तो यह बदल जाता है x किसी भी यादृच्छिक हेक्स अंक के साथ, y यादृच्छिक डेटा के साथ (शीर्ष 2 बिट्स को मजबूर करने के अलावा 10 आरएफसी स्पेक के अनुसार), और रेगेक्स मेल नहीं खाता है - या 4 पात्र, इसलिए उन्हें उनके साथ सौदा करने की ज़रूरत नहीं है। बहुत, बहुत चालाक।

पहली बात यह जानना है कि फ़ंक्शन कॉल महंगे हैं, जैसे कि नियमित अभिव्यक्तियां हैं (हालांकि वह केवल 1 का उपयोग करता है, इसमें 32 कॉलबैक हैं, प्रत्येक मैच के लिए एक है, और 32 कॉलबैक में से प्रत्येक में यह Math.random () और v को कॉल करता है। toString (16))।

प्रदर्शन की ओर पहला कदम RegEx और उसके कॉलबैक फ़ंक्शंस को खत्म करना और इसके बजाय एक साधारण लूप का उपयोग करना है। इसका मतलब है कि हमें इससे निपटना होगा - तथा 4 चरित्र जबकि ब्रोफा नहीं था। साथ ही, ध्यान दें कि हम अपनी स्लिम स्ट्रिंग टेम्पलेट आर्किटेक्चर रखने के लिए स्ट्रिंग ऐरे इंडेक्सिंग का उपयोग कर सकते हैं:

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

असल में, एक ही आंतरिक तर्क, सिवाय इसके कि हम जांच करते हैं - या 4, और थोड़ी देर लूप का उपयोग (इसके बजाए replace() कॉलबैक) हमें लगभग 3 एक्स सुधार प्राप्त करता है!

अगला कदम डेस्कटॉप पर एक छोटा सा है लेकिन मोबाइल पर एक अच्छा अंतर बनाता है। आइए कम गणित करें। यादृच्छिक () कॉल करें और उनमें से 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
}

यह प्लेटफार्म के आधार पर हमें 10-30% बचाता है। बुरा नहीं। लेकिन अगला बड़ा कदम टूस्टिंग फ़ंक्शन से छुटकारा पाता है, ऑप्टिमाइज़ेशन क्लासिक - लुक-अप टेबल के साथ पूरी तरह से कॉल करता है। एक साधारण 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
}

अगला अनुकूलन एक और क्लासिक है। चूंकि हम केवल प्रत्येक लूप पुनरावृत्ति में आउटपुट के 4-बिट्स को संभालने वाले हैं, चलो आधे में लूप की संख्या में कटौती करें और प्रत्येक पुनरावृत्ति 8-बिट्स को संसाधित करें। यह मुश्किल है क्योंकि हमें अभी भी आरएफसी अनुपालन बिट स्थिति को संभालना है, लेकिन यह बहुत कठिन नहीं है। हमें 0x00 - 0xff स्टोर करने के लिए एक बड़ी लुकअप टेबल (16x16, या 256) बनाना है, और हम इसे e5 () फ़ंक्शन के बाहर केवल एक बार बनाते हैं।

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e5() {
  var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];
  var u='',i=0,rb=Math.random()*0xffffffff|0;
  while(i++<20) {
    var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));
    u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8
  }
  return u
}

मैंने एक ई 6 () की कोशिश की जो एक समय में 16-बिट्स को संसाधित करता है, फिर भी 256-तत्व LUT का उपयोग करता है, और यह ऑप्टिमाइज़ेशन के घटते रिटर्न दिखाता है। हालांकि इसमें कम पुनरावृत्ति थी, आंतरिक तर्क जटिल प्रसंस्करण से जटिल था, और यह डेस्कटॉप पर और मोबाइल पर केवल ~ 10% तेज प्रदर्शन करता था।

आवेदन करने के लिए अंतिम अनुकूलन तकनीक - लूप अनलोल करें। चूंकि हम निश्चित समय को लूप कर रहे हैं, इसलिए हम इसे तकनीकी रूप से हाथ से लिख सकते हैं। मैंने एक बार एक यादृच्छिक परिवर्तनीय आर के साथ यह कोशिश की कि मैंने फिर से असाइन किया है, और प्रदर्शन टैंक किया गया है। लेकिन चार चर के साथ यादृच्छिक डेटा को सामने रखा गया है, फिर लुकअप टेबल का उपयोग करके, और उचित आरएफसी बिट्स को लागू करने के साथ, यह संस्करण उन सभी को धूम्रपान करता है:

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

Modualized: http://jcward.com/UUID.js - UUID.generate()

मजाकिया बात यह है कि यादृच्छिक डेटा के 16 बाइट उत्पन्न करना आसान हिस्सा है। पूरी चाल इसे आरएफसी अनुपालन के साथ स्ट्रिंग प्रारूप में व्यक्त कर रही है, और यह यादृच्छिक डेटा के 16 बाइट्स, एक अनियंत्रित लूप और लुकअप टेबल के साथ सबसे कड़ाई से पूरा किया गया है।

मुझे उम्मीद है कि मेरा तर्क सही है - इस तरह के कठिन काम में गलती करना बहुत आसान है। लेकिन आउटपुट मेरे लिए अच्छा लग रहा है। मुझे उम्मीद है कि आपने कोड अनुकूलन के माध्यम से इस पागल सवारी का आनंद लिया!

आपको सलाह दी जाती है: मेरा प्राथमिक लक्ष्य संभावित अनुकूलन रणनीतियों को दिखाने और सिखाना था। अन्य उत्तरों टकराव और वास्तव में यादृच्छिक संख्या जैसे महत्वपूर्ण विषयों को कवर करते हैं, जो अच्छे यूयूआईडी उत्पन्न करने के लिए महत्वपूर्ण हैं।


308



jsperf.com आपको डेटा कैप्चर करने और ब्राउज़र और उपकरणों के परिणामों को देखने की अनुमति देगा। - fearphage
हाय @ चाड, अच्छे सवाल। के बाहर बाहर ले जाया जा सकता है, लेकिन इससे ऊपर प्रदर्शन में सुधार नहीं हुआ और स्कोप मैसियर बनाता है। और एक सरणी का निर्माण और वापसी पर शामिल होने से अजीब प्रदर्शन खराब हो जाता है। लेकिन फिर, प्रयोग करने के लिए स्वतंत्र महसूस करें! - Jeff Ward
मैं यह देखने के लिए उत्सुक होगा कि कैसे node-uuid.js तुलना करता है। मेरे काम में मैंने प्रदर्शन पर अधिक ध्यान देने के साथ शुरुआत की, जिनमें से कुछ बनी हुई है। लेकिन मैंने तब से इसका समर्थन किया है, अधिक पढ़ने योग्य / रखरखाव कोड पसंद करते हैं। कारण यह है कि यूयूआईडी परफ वास्तविक दुनिया में कोई मुद्दा नहीं है। यूयूड्स आमतौर पर बहुत धीमी परिचालनों के संयोजन के साथ बनाए जाते हैं (उदाहरण के लिए एक नेटवर्क ऑब्जेक्ट बनाना, मॉडल ऑब्जेक्ट बनाना और बनाए रखना), जहां चीजों से कुछ माइक्रोसेकंड शेविंग करना कोई फर्क नहीं पड़ता। - broofa
इस कोड में अभी भी कुछ त्रुटियां हैं: Math.random()*0xFFFFFFFF लाइनें होनी चाहिए Math.random()*0x100000000 पूर्ण यादृच्छिकता के लिए, और >>>0 इसके बजाय इस्तेमाल किया जाना चाहिए |0 मूल्यों को हस्ताक्षरित रखने के लिए (हालांकि वर्तमान कोड के साथ मुझे लगता है कि यह ठीक हो गया है, भले ही वे हस्ताक्षरित हैं)। आखिरकार इन दिनों उपयोग करने के लिए यह एक बहुत अच्छा विचार होगा window.crypto.getRandomValues यदि उपलब्ध हो, और Math- के लिए वापस आना। केवल तभी याद रखें जब बिल्कुल आवश्यक हो। Math.random के पास 128 बिट से कम एंट्रॉपी हो सकती है, इस मामले में यह आवश्यक से टकराव के लिए अधिक असुरक्षित होगा। - Dave
@ डेव की सभी सलाहयां लागू की हैं और यहां बहुत साफ ES6 / Babel स्रोत प्रकाशित किया है: codepen.io/avesus/pen/wgQmaV?editors=0012 - Brian Haak


यहां कुछ कोड दिया गया है आरएफसी 4122, सेक्शन 4.4 (ट्रूली रैंडम या छद्म-यादृच्छिक संख्या से यूयूआईडी बनाने के लिए एल्गोरिदम)।

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

138



यह सी # के लिए सिस्टम को पार्स करने के लिए आवश्यक डैश का उत्पादन नहीं करता है। गुड। यह इस तरह प्रस्तुत करता है: B42A153F1D9A4F92990392C11DD684D2, जब इसे प्रस्तुत करना चाहिए: B42A153F-1D9A-4F92-9903-92C11DD684D2 - Levitikon
Spec से एबीएनएफ में वर्णों को शामिल किया गया है, इसलिए मैंने अनुपालन के लिए अद्यतन किया। - Kevin Hakanson
मैं व्यक्तिगत रूप से डैश से नफरत करता हूं, लेकिन प्रत्येक के लिए। अरे, यही कारण है कि हम प्रोग्रामर हैं! - devios1
जब आप GUID बनाते हैं तो आपको इसे गतिशील रूप से आकार देने के बजाए पहले सरणी आकार घोषित करना चाहिए। var s = new Array(36); - MgSam
@ लेविटिकॉन .NET है Guid.Parse() पार्स होना चाहिए B42A153F1D9A4F92990392C11DD684D2 एक ग्रिड में बस ठीक है। इसमें हाइफ़न होने की आवश्यकता नहीं है। - JLRishe


प्रारूप में स्ट्रिंग जेनरेटर विधि की तरह सबसे तेज़ 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 (slavik@meltser.info).
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

प्रदर्शन का परीक्षण करने के लिए, आप यह कोड चला सकते हैं:

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

मुझे यकीन है कि आप में से अधिकांश समझेंगे कि मैंने वहां क्या किया है, लेकिन शायद कम से कम एक व्यक्ति है जिसे स्पष्टीकरण की आवश्यकता होगी:

एल्गोरिदम:

  • Math.random() फ़ंक्शन दशमलव अंश बिंदु के बाद 16 अंकों के साथ 0 और 1 के बीच दशमलव संख्या देता है (के लिए उदाहरण 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"), और उसके बाद आठ वर्णों की लंबाई के साथ दूसरी अनुक्रमणिका (तीसरा चरित्र) से इसे काट दिया। शेष मामलों के लिए, शून्य के अतिरिक्त परिणाम को नुकसान नहीं पहुंचाएगा क्योंकि यह इसे किसी भी तरह से काट रहा है।
    Math.random().toString(16)+"000000000").substr(2,8)

सभा:

  • GUID निम्नलिखित प्रारूप में है XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
  • मैंने GUID को 4 टुकड़ों में विभाजित किया, प्रत्येक टुकड़ा 2 प्रकार (या स्वरूप) में विभाजित: XXXXXXXX तथा -XXXX-XXXX
  • अब मैं निम्न 4 प्रकारों के साथ GUID को इकट्ठा करने के लिए इन 2 प्रकारों का उपयोग करके GUID का निर्माण कर रहा हूं, निम्नानुसार: XXXXXXXX  -XXXX-XXXX  -XXXX-XXXX  XXXXXXXX
  • इन दो प्रकारों के बीच अंतर करने के लिए, मैंने एक जोड़ी निर्माता फ़ंक्शन में ध्वज पैरामीटर जोड़ा _p8(s), द s पैरामीटर फ़ंक्शन को बताता है कि डैश जोड़ने या नहीं।
  • आखिरकार हम निम्नलिखित श्रृंखला के साथ GUID बनाते हैं: _p8() + _p8(true) + _p8(true) + _p8(), और इसे वापस करो।

मेरे ब्लॉग पर इस पोस्ट से लिंक करें

का आनंद लें! :-)


79



यह कार्यान्वयन गलत है। GUID के कुछ पात्रों को विशेष उपचार की आवश्यकता होती है (उदाहरण के लिए 13 वां अंक संख्या 4 होना चाहिए)। - JLRishe
@ जेएलआरशी, आप सही हैं, यह आरएफसी 4122 मानकों का पालन नहीं करता है। लेकिन यह अभी भी एक यादृच्छिक स्ट्रिंग है जो GUID की तरह दिखता है। चीयर्स :-) - Slavik Meltser
अच्छा काम है, लेकिन क्लासिक ऑप्टिमाइज़ेशन तकनीकें इसे 6 एक्स तेज बनाती हैं (मेरे ब्राउज़र पर) - देखें मेरा जवाब - Jeff Ward


var uniqueId = Math.random().toString(36).substring(2) 
               + (new Date()).getTime().toString(36);

यदि आईडी 1 मिलीसेकंड से अधिक उत्पन्न होती है, तो वे 100% अद्वितीय हैं।

यदि छोटे अंतराल पर दो आईडी उत्पन्न होते हैं, और यह मानते हुए कि यादृच्छिक विधि वास्तव में यादृच्छिक है, तो यह 99 उत्पन्न हो जाएगा जो 99.9 99 99 99 99 99 999% वैश्विक रूप से अद्वितीय होने की संभावना है (10 ^ 15 में से टक्कर)

आप अधिक अंक जोड़कर इस नंबर को बढ़ा सकते हैं, लेकिन 100% अद्वितीय आईडी उत्पन्न करने के लिए आपको वैश्विक काउंटर का उपयोग करने की आवश्यकता होगी।

document.getElementById("unique").innerHTML =
  Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
<div id="unique">
</div>


69



हालांकि यह यूयूआईडी नहीं है? - Marco Kerwitz
नहीं। यूयूआईडी / GUID एक 122 बिट (+ छह आरक्षित बिट्स) संख्या है। यह वैश्विक काउंटर सेवा के माध्यम से विशिष्टता की गारंटी दे सकता है, लेकिन अक्सर यह समय, मैक पता और यादृच्छिकता पर निर्भर करता है। यूयूआईडी यादृच्छिक नहीं हैं! यूआईडी मैं यहां सुझाव देता हूं पूरी तरह संपीड़ित नहीं है। आप इसे 122 बिट पूर्णांक तक संकुचित कर सकते हैं, 6 पूर्व परिभाषित बिट्स और अतिरिक्त यादृच्छिक बिट्स (कुछ टाइमर बिट्स को हटाएं) जोड़ें और आप पूरी तरह से गठित यूयूआईडी / GUID के साथ समाप्त हो जाते हैं, जिसे आपको हेक्स में परिवर्तित करना होगा। मेरे लिए जो वास्तव में आईडी की लंबाई के अनुपालन के अलावा कुछ भी नहीं जोड़ता है। - Simon Rigét
आभासी मशीनों पर विशिष्टता के लिए मैक पते पर रिलेइंग एक बुरा विचार है! - Simon Rigét