Soru JavaScript'te GUID / UUID oluşturulsun mu?


JavaScript'te global olarak benzersiz tanımlayıcılar oluşturmaya çalışıyorum. Tüm tarayıcılarda rutinlerin ne olduğundan, "rastgele" ve yerleşik rasgele sayı üretecinin nasıl tohumlanacağından emin değilim.

GUID / UUID en az 32 karakterden oluşmalı ve ASCII aralığında kalmalı ve bunları aşarken sorun çıkmamalıdır.


3219


Menşei


Dizgiler olarak bildirildiğinde GUID'ler en az 36 ve en fazla 38 karakter uzunluğundadır ve ^ \ {? [A-zA-Z0-9] {36}? \} $ Deseniyle eşleşir ve dolayısıyla her zaman asci'dir. - AnthonyWJones
David Bau, çok daha iyi, görülebilir rastgele sayı üreteci sağlar davidbau.com/archives/2010/01/30/... UUID'leri üretmek için biraz farklı bir yaklaşım yazdım. blogs.cozi.com/tech/2010/04/generating-uuids-in-javascript.html - George V. Reilly
jsben.ch/#/Lbxoe - aşağıdan farklı işlevlerle burada bir kıyaslama - EscapeNetscape
Uuid rasgele iyi PRNG kullanır ve çok hızlıdır. - jchook
Burada parti için geç (çok geç!) Ama @AnthonyWJones regex'inizi okumaz: ^ \ {? [A-fA-F0-9] {36}? \} $ - noonand


Cevaplar:


Bu konuda birkaç girişim var. Soru şu: gerçek GUID'leri mi yoksa sadece rastgele sayıları mı istiyorsunuz? bak GUID'ler gibi mi? Rasgele sayılar üretmek için yeterince kolaydır.

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

Ancak, bu değerlere dikkat edin orijinal GUID'ler değil.

Javascript'te gerçek GUID'leri oluşturmanın bir yolu yoktur, çünkü tarayıcıların açığa çıkmadığı yerel bilgisayarın özelliklerine bağlıdırlar. ActiveX gibi OS'ye özgü hizmetleri kullanmanız gerekir: http://p2p.wrox.com/topicindex/20339.htm

Düzenleme: doğru değil - RFC4122 rasgele ("sürüm 4") GUID'lere izin verir. Ayrıntılar için diğer cevapları gör.

Not: sağlanan kod snippet'i, sürümün gerektirdiği RFC4122'yi takip etmiyor (4) oluşturulan çıkış dizesine entegre edilmelidir. Bu cevap kullanmayın uyumlu GUID'lere ihtiyacınız varsa.

kullanın:

var uuid = guid();

Demo:

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



Aslında RFC, rasgele sayılardan oluşturulan UUID'lere izin verir. Bunu tanımlamak için birkaç bit bulmanız yeterlidir. Bölüm 4.4'e bakınız. Gerçekten Rastgele veya Sözde Rastgele Sayılardan UUID Oluşturma Algoritmaları: rfc-archive.org/getrfc.php?rfc=4122 - Jason DeFontes
Birisi bu kodu bana açıklayabilir mi? S4 işlevinin, 0x10000 ile 0x20000 arasında rastgele bir onaltılık sayı almayı denediği görülüyor, ardından son 4 basamağı çıkıyor. Ama neden bitsel veya 0 ile? Bu bir noop olmasın mı? Ayrıca, önde gelen 0'larla uğraşmaktan kaçınmak için 0x10000 - 0x20000 sadece bir hack nedir? - Cory
Chrome'da bu kod her zaman doğru boyutlu bir GUID oluşturmaz. Uzunluk 35 ve 36 arasında değişir - cdeutsch
Açıkça yanlış bir cevap nasıl bu kadar çok upvotes alabilir? Doğru konumda 4 olmadığı için kod bile yanlış. en.wikipedia.org/wiki/Globally_unique_identifier - Dennis Krøger
Bu cevap, "1 + ...." ve "substring (1)" kaldırıldığında revizyon 5'de kırıldı. Bu bitler tutarlı uzunluğu garanti etti. - Segfault


Bir ... için RFC4122 sürüm 4 uyumlu çözüm, bu one-liner (ish) çözümü ile gelebilir en kompakt:

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

Güncelleme, 2015-06-02: UUID benzersizliğinin altta yatan rasgele sayı üretecine (RNG) bağlı olduğunu unutmayın. Yukarıdaki çözüm kullanır Math.random() Ancak, kısırlık için Math.random() olduğu değil Yüksek kaliteli bir RNG olması garantilidir. Adam Hyland'ın Gör Math.random () üzerinde mükemmel bir yazma detaylar için. Daha sağlam bir çözüm için, şöyle bir şey düşünün uuid modülü[Feragatname: Ben yazarım], mevcut olduğunda daha yüksek kalitede RNG API'leri kullanır.

Güncelleme, 2015-08-26: Bir yan not olarak, bu öz Belirli bir çarpışma olasılığına ulaşmadan önce kaç tane kimliğin üretilebileceğini açıklar. Örneğin, 3.26x10 ile15 sürüm 4 RFC4122 UUID'lerin 1 milyon bir çarpışma şansı var.

Güncelleme, 2017-06-28: A Chrome geliştiricilerinden iyi bir makale Chrome, Firefox ve Safari'de Math.random PRNG kalitesinin durumunu tartışıyor. tl; dr - 2015'in sonu itibariyle "oldukça iyi", ancak şifreleme kalitesi değil. Bu sorunu çözmek için, ES6'yı kullanan yukarıdaki çözümün güncelleştirilmiş bir sürümünü burada bulabilirsiniz. crypto API ve biraz JS sihirbazlık için kredi alamıyorum:

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



Bu kodu istemcideki benzersiz kimlikler için kullanmak güvenli midir ve daha sonra bu kimlikleri sunucudaki nesneleri kaydetmek için birincil anahtarlar olarak mı kullanıyorsunuz? - Muxa
... (devamı) Bu işlev tarafından çarpışan iki Kimliğin olasılıkları, tam anlamıyla, astronomik olarak küçüktür. Kimliğin 128 bitinin 6'sı hariç hepsi rastgele oluşturulmuştur, yani herhangi bir iki kimlik için, çarpışacakları bir 2 ^^ 122 (veya 5.3x10 ^^ 36) şansı vardır. - broofa
Çarpışmalarla ilgili bir soru gönderdim stackoverflow.com/questions/6906916/... - Muxa
Muhtemelen @ Muxa'nın sorusu cevabı 'hayır' mı? Müşteriden gelen bir şeye güvenmek asla güvenilir değildir. Kullanıcılarınızın bir javascript konsolu oluşturup, değişkeni el ile değiştirmek istediklerine göre değiştireceklerine inanırım. Ya da sadece istedikleri kimliği geri gönderebilirler. Ayrıca, kullanıcının kendi kimliğini seçmesinin güvenlik açıklarına neden olup olmayacağı da değişir. Her iki durumda da, eğer bir tabloya giren rastgele bir sayı kimliği ise, muhtemelen sunucu tarafında üretecektim, böylece süreç üzerinde kontrol sahibi olduğumu biliyorum. - Cam Jackson
@DrewNoakes - UUID'ler sadece rastgele # lerden ibaret değildir. "4" uuid versiyonudur (4 = "random"). "Y", uuid varyantının (temel olarak alan düzeninin) gömülü olması gerektiğini gösterir. Bölüm 4.1.1 ve 4.1.3'e bakınız. ietf.org/rfc/rfc4122.txt daha fazla bilgi için. - broofa


Gerçekten ne kadar temizim Broofa'nın cevabı ama, bu zayıf uygulamaların talihsizliği Math.random çarpışma şansını bırak.

İşte benzer RFC4122 ilk 13 onaltılık sayıları zaman damgasının bir hex kısmı ile dengeleyerek bu sorunu çözen sürüm 4 uyumlu bir çözüm. Bu şekilde bile Math.randomaynı tohum üzerinde, aynı UUID almak için her iki istemcinin aynı milisaniyede (veya 10.000+ yıl sonra) UUID üretmesi gerekir:

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


İşte test etmek için bir keman var.


672



Aklında ayı, new Date().getTime() her milisaniyede güncellenmez. Bunun, algoritmanızın beklenen rasgeleliğini nasıl etkilediğinden emin değilim. - devios1
Bunun en iyi cevaplar olduğunu düşünüyorum, çünkü o, nesnedeki tarihi kullanıyor. Ancak, modern bir tarayıcı kümeniz varsa Date.now() için new Date().getTime() - Fresheyeball
performance.now daha iyi olurdu. Date.now öğesinden farklı olarak, döndürülen zaman damgaları performance.now() bir milisaniye çözünürlüğü ile sınırlı değildir. Bunun yerine, zamanla kayan nokta sayıları olarak zamanları temsil ederler. mikro saniye kesin. Ayrıca, Date.now öğesinden farklı olarak, performance.now () tarafından döndürülen değerler her zaman sabit bir oranda artarAğ Zaman Protokolü gibi bir yazılım tarafından elle ayarlanabilen veya eğrilen sistem saatinden bağımsız olarak. - daniellmb
@daniellmb Muhtemelen MDN'ye veya bir başkasına gerçek dokümantasyon göstermek için bir polyfill'e bağlı olmalısınız;) - Martin
FYI, site altbilgisine göre, sitedeki tüm kullanıcı katkıları cc by-sa 3.0 lisansı altındadır. - Xiong Chiamiov


broofa'nın cevabı oldukça kaygan, gerçekten - etkileyici zeki, gerçekten ... rfc4122 uyumlu, biraz okunabilir ve kompakt. Korku veren!

Ama bu normal ifadeye bakıyorsanız, o kadar çok replace() geri aramalar toString()ve Math.random() işlev çağrıları (yalnızca 4 bitlik sonucu kullanıyor ve gerisini boşa harcıyor), performans hakkında merak etmeye başlayabilirsiniz. Gerçekten de, joelpt bile RFC ile genel GUID hızını atmaya karar verdi. generateQuickGUID.

Ama hız alabilir miyiz? ve RFC uyumluluğu? Evet dedim!  Okunabilirliği koruyabilir miyiz? Şey ... Pek değil, ama devam edersen çok kolay.

Ama önce, sonuçlarım, broofa'ya kıyasla, guid (kabul edilen cevap) ve rfc uyumlu değil 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.

Bu yüzden benim 6. yineleme optimizasyonumla, en popüler cevabı devrediyorum 12X, kabul edilen cevap üzerine 9Xve hızlı-uyumlu olmayan cevap 2-3 x. Ve hala rfc4122 uyumlu değilim.

Nasıl ilgileniyor? Tüm kaynağı açtım http://jsfiddle.net/jcward/7hyaC/3/ ve üzerinde http://jsperf.com/uuid-generator-opt/4

Bir açıklama için, broofa'nın koduyla başlayalım:

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

Yani yerini alır x herhangi bir rasgele altıgen rakam ile, y rastgele verilerle (en üst 2 bite zorlamak hariç) 10 RFC speklerine göre) ve regex eşleşmiyor - veya 4 karakterler, onlarla uğraşmak zorunda değil. Çok, çok kaygan.

Bilmeniz gereken ilk şey, normal ifadeler olduğu gibi fonksiyon çağrılarının pahalı olmasıdır (sadece 1 kullanıyor olsa da, 32 tane geri arama, her maç için bir tane ve Math.random () ve v. toString (16)).

Performansa yönelik ilk adım, RegEx ve geri arama işlevlerini ortadan kaldırmak ve bunun yerine basit bir döngü kullanmaktır. Bu, bizim - ve 4 broofa olmasa da karakterler. Ayrıca, String Dizisi mimarisini tutmak için String Dizisi dizinlemesini kullanabileceğimizi de unutmayın:

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

Temel olarak, aynı iç mantık, kontrol etmemiz hariç - veya 4ve bir süre döngü kullanmak yerine replace() Geri aramalar) bizi neredeyse 3 katına çıkarıyor!

Bir sonraki adım masaüstünde küçük ama mobilde iyi bir fark yaratıyor. Daha az Math.random () çağrısı yapalım ve bunların% 87'sini, her bir yinelemeyi değiştirecek rastgele bir tamponla atmak yerine, tüm bu rastgele bitleri kullanalım. Aynı zamanda yardımcı olması durumunda, bu şablon tanımını döngüden de çıkaralım:

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
}

Bu, platforma bağlı olarak% 10-30 oranında tasarruf sağlıyor. Fena değil. Ama bir sonraki büyük adım, bir optimizasyon klasiği olan toString işlev çağrılarını tamamen ortadan kaldırıyor. Basit bir 16 elemanlı arama tablosu, toString (16) işini çok daha kısa sürede gerçekleştirir:

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
}

Bir sonraki optimizasyon başka bir klasik. Her döngü yinelemesinde sadece 4-bitlik çıktıları kullandığımızdan, döngü sayısını yarıya indirelim ve her bir yinelemeyi 8-bit yapalım. Bu, hala RFC uyumlu bit konumlarını işlemek zorunda olduğumuz için zor, ancak çok zor değil. Daha sonra 0x00 - 0xff dosyasını saklamak için daha büyük bir arama tablosu (16x16 veya 256) yapmalıyız ve bunu yalnızca bir kez e5 () işlevinin dışında oluşturuyoruz.

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
}

Bir kerede, 16-bitleri 256-element LUT kullanarak işleyen bir e6 () çalıştı ve optimizasyonun azalan getirisini gösterdi. Her ne kadar daha az yineleme olsa da, iç mantık artan işlemle karmaşıktı ve aynı şeyi masaüstünde gerçekleştirdi ve sadece mobil cihazlarda% 10 daha hızlıydı.

Uygulanacak son optimizasyon tekniği - döngüyü açın. Sabit sayıda defa döngü yaptığımız için, teknik olarak bunu el ile yazabiliriz. Bunu bir kez yeniden atayarak tuttuğum tek bir rasgele değişkenle ve performans tankıyla denedim. Ancak, dört değişkene rastgele veriyi önden atama, ardından arama tablosunu kullanma ve uygun RFC bitlerini uygulama, bu sürüm hepsini içiyor:

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

Komik olan, 16 baytlık rastgele veri üreten kolay kısımdır. Tüm hile, RFC uyumu ile dize formatında ifade ediyor ve en çok rastgele 16 bit veri, bir döngü ve arama tablosu ile gerçekleştirildi.

Umarım mantığım doğrudur - bu tarz bir can sıkıcı işte bir hata yapmak çok kolaydır. Ama çıktılar bana iyi görünüyor. Umarım kod optimizasyonu ile bu çılgın yolculuğun tadını çıkarmışsınızdır!

Tavsiye olun: birincil hedefim potansiyel optimizasyon stratejilerini göstermek ve öğretmek oldu. Diğer cevaplar, iyi UUID'ler oluşturmak için önemli olan çarpışmalar ve gerçekten rastgele sayılar gibi önemli konuları kapsamaktadır.


308



jsperf.com Verileri yakalamanıza ve sonuçları tarayıcılarda ve cihazlarda görmenizi sağlar. - fearphage
Merhaba @chad, iyi sorular. k dışarıdan taşınabiliyordu, ancak bu yukarıdaki performansı iyileştirmedi ve kapsamı daha da karmaşık hale getirdi. Ve bir dizi inşa etmek ve dönüşe katılmak bir araya geldiğinde performansı öldürüyor. Ama yine de deney yapmaktan çekinmeyin! - Jeff Ward
Node-uuid.js'nin nasıl karşılaştırıldığını görmek isterim. Çalışmamda, performansa odaklanmaya başlamıştım, bazıları da devam ediyor. Ama o zamandan beri daha okunabilir / sürdürülebilir bir koda sahip olmayı tercih ettim. Uuid mükemmel olmanın nedeni, gerçek dünyada basit bir sorun değildir. Uuidler tipik olarak, çok daha yavaş işlemlerle (ör. Bir ağ talebi yapmak, bir model nesneyi yaratmak ve devam ettirmek) birlikte, bir kaç mikrosaniyeyi tıraş etmek basitçe önemli değildir. - broofa
Bu kod hala birkaç hata içeriyor: Math.random()*0xFFFFFFFF çizgiler olmalı Math.random()*0x100000000 tam rastgelelik için, ve >>>0 yerine kullanılmalıdır |0 Değerleri imzasız tutmak için (geçerli kod ile olsa da, imzalı olsalar bile OK alır). Son olarak bugünlerde kullanmak çok güzel bir fikir olurdu. window.crypto.getRandomValues Varsa ve yalnızca kesinlikle gerekliyse Math.random'a geri dönün. Math.random, 128 bit entropi değerine sahip olabilir, bu durumda bu, çarpışmalardan daha hassastır. - Dave
@Dave'in tüm tavsiyelerini uyguladınız ve çok düzgün bir ES6 / Babel kaynağını burada yayınladınız: codepen.io/avesus/pen/wgQmaV?editors=0012 - Brian Haak


İşte bazı kodlar RFC 4122, bölüm 4.4 (Gerçekten Rasgele veya Sözde Rastgele Sayıdan bir UUID Oluşturma Algoritmaları).

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



Bu, c # için onu System.Guid'e ayrıştırmak için gereken tire çizgilerini üretmez. B42A153F1D9A4F92990392C11DD684D2, şu şekilde işlenir: B42A153F-1D9A-4F92-9903-92C11DD684D2 - Levitikon
Spesifikasyondaki ABNF, "-" karakterlerini içerir, bu yüzden uyumlu olmayı güncelledim. - Kevin Hakanson
Şahsen nefret ediyorum, ama her biri için. Hey bu yüzden programcıyız! - devios1
GUID'yi oluştururken dinamik olarak boyutlandırmak yerine dizi boyutunu önceden bildirmelisiniz. var s = new Array(36); - MgSam
@Levitikon .NET'in Guid.Parse() ayrıştırmalı B42A153F1D9A4F92990392C11DD684D2 bir Guid içine sadece iyi. Tire'ye sahip olmak zorunda değil. - JLRishe


Biçiminde en hızlı GUID string generator yöntemi XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Bu, standart uyumlu GUID oluşturmaz.

Bu uygulamanın on milyon icraatı sadece 32.5 saniye sürüyor, ki bu bir tarayıcıda gördüğüm en hızlısıdır (döngü / yineleme olmadan tek çözüm).

İşlev şu kadar basit:

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

Performansı test etmek için bu kodu çalıştırabilirsiniz:

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

Eminim çoğunuz orada ne yaptığımı anlayacaktır, ama belki de bir açıklama gerektirecek en az bir kişi var:

Algoritma:

  • Math.random() işlevi, ondalık kesir noktasından sonra 16 basamaklı 0 ve 1 arasında bir ondalık sayı döndürür örnek 0.4363923368509859).
  • Sonra bu numarayı alıp dönüştürürüz 16 numaralı bir dizgeye (yukarıdaki örnekte alacağız) 0.6fb7687f).
    Math.random().toString(16).
  • Sonra biz kestik 0. önek (0.6fb7687f => 6fb7687f) ve sekiz onaltılık bir dize olsun karakter uzunluğu.
    (Math.random().toString(16).substr(2,8).
  • Bazen Math.random()işlev dönecek daha kısa sayı (örneğin 0.4363), sonunda sıfırlar nedeniyle (yukarıdaki örnekte, aslında sayı 0.4363000000000000). Bu yüzden bu dizeye ekliyorum "000000000" (dokuz sıfır ile bir dize) ve ardından keserek substr() Tam olarak dokuz karakter yapmak için işlev (sağa doğru sıfırlar).
  • Tam olarak dokuz sıfır eklemenin nedeni, daha kötü durum senaryosundan kaynaklanmaktadır. Math.random() işlev tam olarak 0 veya 1 (her biri için 1/10 ^ 16 olasılık) döndürecektir. Bu yüzden ona dokuz sıfır eklememiz gerekiyordu ("0"+"000000000" veya "1"+"000000000") ve sonra sekiz karakter uzunluğunda ikinci indeks (3. karakter) keserek. Davaların geri kalanı için, sıfırların eklenmesi sonuca zarar vermeyecektir, çünkü yine de onu kesiyor.
    Math.random().toString(16)+"000000000").substr(2,8).

Montaj:

  • GUID aşağıdaki biçimde XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • GUID'yi 4 parçaya böldüm, her parça 2 türe (veya formata) ayrıldı: XXXXXXXX ve -XXXX-XXXX.
  • Şimdi GUID'yi şu 4 adet çağrı ile birleştirmek için şu 2 tipini kullanarak yapıyorum: XXXXXXXX  -XXXX-XXXX  -XXXX-XXXX  XXXXXXXX.
  • Bu iki tür arasında farklılık göstermek için, bir eş oluşturma işlevine bir bayrak parametresi ekledim _p8(s), s parametresi, tire eklenip eklenmeyeceğini işleve bildirir.
  • Sonunda GUID'yi aşağıdaki zincirle oluşturuyoruz: _p8() + _p8(true) + _p8(true) + _p8()ve geri ver.

Blog'umdaki bu yayına bağlantı oluştur

Keyfini çıkarın! :-)


79



Bu uygulama yanlış. GUID'in belirli karakterleri özel işlem gerektirir (örn. 13. rakamın 4 rakamı olması gerekir). - JLRishe
@JLRishe, haklısınız, RFC4122 standartlarına uymuyor. Ama yine de GUID gibi görünen rastgele bir dizedir. Şerefe :-) - Slavik Meltser
Güzel çalışma, ancak klasik optimizasyon teknikleri 6X'i daha hızlı hale getiriyor (tarayıcımda) - bkz. cevabım - Jeff Ward


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

Eğer ID'ler birbirinden 1 milisaniyeden daha uzakta üretilirse,% 100 benzersizdir.

Eğer iki ID daha kısa aralıklarla üretilirse ve rastgele yöntemin gerçekten rasgele olduğunu varsayarsak, bu% 99.99999999999999% 'lük genel olarak benzersiz olma ihtimali olan ID'leri üretecektir (10 ^ 15'in 1'inde çarpışma)

Daha fazla rakam ekleyerek bu sayıyı artırabilirsiniz, ancak% 100 benzersiz kimlikler oluşturmak için küresel bir sayaç kullanmanız gerekecektir.

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


69



Bu UUID değil mi? - Marco Kerwitz
Hayır. UUID / GUID'ler 122 bit (+ altı ayrılmış bit) sayısıdır. Küresel bir karşı hizmet aracılığıyla benzersizliği garanti edebilir, ancak çoğu zaman, MAC adresi ve rastgeleliği zamanla röleler. UUID'ler rastgele değil! Burada önerdiğim UID tamamen sıkıştırılmamış. Bunu, 122 bitlik bir tam sayıya sıkıştırabilir, önceden tanımlanmış 6 biti ve fazladan rastgele bitleri (birkaç zamanlayıcı biti çıkar) ekleyebilir ve mükemmel bir şekilde oluşturulmuş UUID / GUID ile sonuçlanırsınız, böylece hex'e dönüştürmeniz gerekir. Bana göre bu, kimliğin uzunluğuna uymaktan başka bir şey eklemiyor. - Simon Rigét
Sanal makinelerde benzersizliğin MAC adreslerinde yeniden oynatılması kötü bir fikir! - Simon Rigét


İşte bir arada en çok oylanan cevapiçin bir çözüm ile Chrome'un çarpışmaları:

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // https://stackoverflow.com/questions/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
        // https://stackoverflow.com/questions/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 üzerinde eğer test etmek istersen.


57



IE'de aslında window.crypto yerine window.msCrypto olduğuna inanıyorum. İkisini de kontrol etmek güzel olabilir. Görmek msdn.microsoft.com/en-us/library/ie/dn265046(v=vs.85).aspx - herbrandson
ilk sürüm, bir `window.crypto.getRandomValues ​​dikkat edin., does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` verir xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx. - humanityANDpeace


İşte bir yorum kullanıcıdan 9 Ekim 2011 tarihli bir çözüm jed en 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)}

Bu, aynı hedefe ulaşır. mevcut en yüksek cevapancak zorlama, özyineleme ve üstel notasyondan yararlanarak 50+ daha az bayt. Meraklı çalışma şekli için, işte fonksiyonun eski bir versiyonunun açıklamalı şekli:

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



TypeScript'te şunu kullanın: export const UUID = function b (a: number): string { return a ? (a^Math.random()*16>>a/4).toString(16) : (''+[1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, b) }; - RyanNerd