Domanda

Sto cercando di creare identificatori univoci a livello globale in JavaScript. Non sono sicuro di quali routine siano disponibili su tutti i browser, come & Quot; random & Quot; e ha seminato il generatore di numeri casuali incorporato, ecc.

Il GUID / UUID deve contenere almeno 32 caratteri e deve rimanere nell'intervallo ASCII per evitare problemi quando li si passa.

È stato utile?

Soluzione

UUID (Universally Unique IDentifier), noto anche come GUID (Globally Unique IDentifier), secondo RFC 4122 , sono identificatori con una certa garanzia di unicità.

Il modo migliore per generarli è seguire le istruzioni di implementazione nella suddetta RFC, utilizzare una delle tante implementazioni open source controllate dalla community.

Un popolare strumento Open Source per lavorare con UUID in JavaScript è node-uuid

Nota che la semplice generazione casuale degli identificatori byte per byte, o carattere per carattere, non ti darà le stesse garanzie di un'implementazione conforme. Inoltre, molto importante, i sistemi che funzionano con UUID conformi possono scegliere di non accettare quelli generati casualmente e molti validatori open source verificheranno effettivamente una struttura valida.

Un UUID deve avere questo formato:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Dove le posizioni M e N possono avere solo determinati valori. Al momento, gli unici valori validi per M sono 1, 2, 3, 4 e 5, quindi generare casualmente quella posizione renderebbe inaccettabile la maggior parte dei risultati.

Altri suggerimenti

Per una soluzione RFC4122 versione 4, questa soluzione one-liner (ish) è il più compatto che ho potuto inventare .:

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

Aggiornamento, 2015-06-02 : tieni presente che l'unicità UUID si basa fortemente sul generatore di numeri casuali sottostante (RNG). La soluzione sopra utilizza Math.random() per brevità, tuttavia crypto non è non garantito come RNG di alta qualità. Vedi eccellente scrittura su Adam.land per Math.random () per maggiori dettagli. Per una soluzione più solida, prendi in considerazione qualcosa come il modulo uuid [Disclaimer: sono l'autore] , che utilizza API RNG di qualità superiore ove disponibili.

Aggiornamento, 26-08-2015 : come nota a margine, questo gist descrive come determinare quanti ID possono essere generati prima di raggiungere una certa probabilità di collisione. Ad esempio, con UUID RFC4122 versione 4 3.26x10 15 hai una probabilità di collisione di 1 su un milione.

Aggiornamento, 28/06/2017 : A buon articolo degli sviluppatori di Chrome che parla dello stato della qualità PRNG di Math.random in Chrome, Firefox e Safari. tl; dr - Alla fine del 2015 è " abbastanza buono " ;, ma non di qualità crittografica. Per risolvere il problema, ecco una versione aggiornata della soluzione di cui sopra che utilizza ES6, l'API <=> e a un po 'di mago JS di cui non posso prendermi il merito :

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

Mi piace davvero quanto sia la risposta di Broofa , ma è un peccato che le cattive implementazioni di Math.random lascino l'occasione per collisione.

Ecco una simile RFC4122 soluzione conforme alla versione 4 che risolve il problema compensando la prima 13 numeri esadecimali per una porzione esadecimale del timestamp. In questo modo, anche se <=> si trova sullo stesso seed, entrambi i client dovrebbero generare l'UUID esattamente nello stesso millisecondo (o più di 10.000 anni dopo) per ottenere lo stesso UUID:

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


Ecco un violino da testare.

La risposta di broofa è piuttosto semplice, davvero - straordinariamente intelligente, davvero ... conforme a rfc4122, in qualche modo leggibile e compatta. Impressionante!

Ma se stai guardando quell'espressione regolare, quei molti replace() callback, le chiamate di funzioni toString() e Math.random() (dove sta usando solo 4 bit del risultato e sprecando il resto), potresti inizia a chiedermi delle prestazioni. In effetti, Joelpt ha persino deciso di lanciare RFC per la velocità GUID generica con generateQuickGUID.

Ma possiamo ottenere velocità e conformità RFC? Dico SÌ! Possiamo mantenere la leggibilità? Beh ... Non proprio, ma è facile se segui.

Ma prima, i miei risultati, rispetto a broofa, guid (la risposta accettata) e la non conforme a 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.

Quindi, con la mia sesta iterazione di ottimizzazioni, ho battuto la risposta più popolare di oltre 12X , la risposta accettata di oltre 9X e la risposta veloce non conforme di 2-3X . E sono ancora conforme a rfc4122.

Interessato a come? Ho messo la fonte completa su http://jsfiddle.net/jcward/7hyaC/3/ e su http://jsperf.com/uuid-generator-opt/4

Per una spiegazione, iniziamo con il codice di broofa:

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

Quindi sostituisce x con qualsiasi cifra esadecimale casuale, y con dati casuali (tranne forzando i primi 2 bit a 10 secondo le specifiche RFC), e il regex non corrisponde a - o 4 personaggi, quindi non deve affrontarli. Molto, molto lucido.

La prima cosa da sapere è che le chiamate di funzione sono costose, così come le espressioni regolari (sebbene usi solo 1, ha 32 callback, una per ogni corrispondenza, e in ognuna delle 32 callback chiama Math.random () e v.toString (16)).

Il primo passo verso le prestazioni è eliminare RegEx e le sue funzioni di callback e utilizzare invece un semplice loop. Questo significa che dobbiamo fare i conti con i caratteri UUID.generate() e <=> mentre Broofa no. Inoltre, tieni presente che possiamo usare l'indicizzazione String Array per mantenere la sua elegante architettura del modello String:

function e1() {
  var u='',i=0;
  while(i++<36) {
    var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);
    u+=(c=='-'||c=='4')?c:v.toString(16)
  }
  return u;
}

Fondamentalmente, la stessa logica interna, tranne che controlliamo per <=> o <=>, e usare un ciclo while (invece di <=> callbacks) ci dà un miglioramento quasi 3X!

Il passaggio successivo è piccolo sul desktop ma fa una discreta differenza sui dispositivi mobili. Facciamo meno chiamate Math.random () e utilizziamo tutti quei bit casuali invece di buttarne via l'87% con un buffer casuale che viene spostato fuori da ogni iterazione. Spostiamo anche quella definizione del modello fuori dal ciclo, nel caso in cui aiuti:

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
}

Questo ci consente di risparmiare il 10-30% a seconda della piattaforma. Non male. Ma il prossimo grande passo si sbarazza delle chiamate alla funzione toString con un classico di ottimizzazione: la tabella di ricerca. Una semplice tabella di ricerca a 16 elementi eseguirà il lavoro di toString (16) in molto meno tempo:

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
}

La prossima ottimizzazione è un altro classico. Dato che gestiamo solo 4 bit di output in ogni iterazione di loop, riduciamo il numero di loop a metà ed elaboriamo 8 bit per ogni iterazione. Questo è difficile poiché dobbiamo ancora gestire le posizioni dei bit conformi a RFC, ma non è troppo difficile. Dobbiamo quindi creare una tabella di ricerca più ampia (16x16 o 256) per memorizzare 0x00 - 0xff e la costruiamo una sola volta, al di fuori della funzione 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
}

Ho provato un e6 () che elabora 16 bit alla volta, usando ancora il LUT a 256 elementi e ha mostrato i rendimenti decrescenti dell'ottimizzazione. Sebbene avesse meno iterazioni, la logica interna era complicata dall'aumento dell'elaborazione e ha funzionato allo stesso modo su desktop e solo ~ 10% più veloce su dispositivi mobili.

La tecnica di ottimizzazione finale da applicare: srotolare il loop. Dal momento che stiamo eseguendo il looping di un numero fisso di volte, possiamo tecnicamente scrivere tutto a mano. L'ho provato una volta con una singola variabile casuale che ho continuato a riassegnare ed eseguirence tankato. Ma con quattro variabili assegnate dati casuali in anticipo, quindi utilizzando la tabella di ricerca e applicando i bit RFC corretti, questa versione li fuma tutti:

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

Modificato: http://jcward.com/UUID.js - <=>

La cosa divertente è che generare 16 byte di dati casuali è la parte facile. L'intero trucco è esprimerlo in formato String con conformità RFC ed è realizzato in modo molto preciso con 16 byte di dati casuali, un ciclo non srotolato e una tabella di ricerca.

Spero che la mia logica sia corretta - è molto facile fare un errore in questo tipo di noioso bit-lavoro. Ma le uscite sembrano buone per me. Spero che ti sia piaciuta questa folle corsa attraverso l'ottimizzazione del codice!

Attenzione: il mio obiettivo principale era mostrare e insegnare potenziali strategie di ottimizzazione. Altre risposte riguardano argomenti importanti come collisioni e numeri veramente casuali, che sono importanti per generare buoni UUID.

Ecco un codice basato su RFC 4122 , sezione 4.4 (Algoritmi per la creazione di un UUID da un numero veramente casuale o pseudo-casuale).

function createUUID() {
    // http://www.ietf.org/rfc/rfc4122.txt
    var s = [];
    var hexDigits = "0123456789abcdef";
    for (var i = 0; i < 36; i++) {
        s[i] = hexDigits.substr(Math.floor(Math.random() * 0x10), 1);
    }
    s[14] = "4";  // bits 12-15 of the time_hi_and_version field to 0010
    s[19] = hexDigits.substr((s[19] & 0x3) | 0x8, 1);  // bits 6-7 of the clock_seq_hi_and_reserved to 01
    s[8] = s[13] = s[18] = s[23] = "-";

    var uuid = s.join("");
    return uuid;
}
var uniqueId = Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);

Se gli ID vengono generati a più di 1 millisecondo di distanza, sono unici al 100%.

Se due ID vengono generati a intervalli più brevi e supponendo che il metodo casuale sia veramente casuale, ciò genererebbe ID con una probabilità del 99,999999999999999% di essere globalmente univoci (collisione in 1 su 10 ^ 15)

Puoi aumentare questo numero aggiungendo più cifre, ma per generare ID univoci al 100% dovrai utilizzare un contatore globale.

se hai davvero bisogno della conformità RFC, questa formattazione passerà come GUID versione 4 valido:

const uid = (new Date()).getTime().toString(16) + Math.random().toString(16).substring(2) + "0".repeat(16);
const guid = uid.substr(0,8) + '-' + uid.substr(8,4) + '-4000-8' + uid.substr(12,3) + '-' + uid.substr(15,12);

Modifica: il codice sopra riportato segue l'intensione, ma non la lettera della RFC. Tra le altre discrepanze, alcune cifre casuali sono brevi. (Aggiungi più cifre casuali se ne hai bisogno) Il lato positivo è che questo è davvero veloce, rispetto al codice conforme al 100%. Puoi testare il tuo GUID qui

GUID più veloce come il metodo generatore di stringhe nel formato XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Questo non genera GUID conforme allo standard.

Dieci milioni di esecuzioni di questa implementazione richiedono solo 32,5 secondi, che è la più veloce che abbia mai visto in un browser (l'unica soluzione senza loop / iterazioni).

La funzione è semplice come:

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

Per testare le prestazioni, puoi eseguire questo codice:

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

Sono sicuro che molti di voi capiranno quello che ho fatto lì, ma forse c'è almeno una persona che avrà bisogno di una spiegazione:

L'algoritmo:

  • La funzione Math.random() restituisce un numero decimale compreso tra 0 e 1 con 16 cifre dopo il punto della frazione decimale (per esempio 0.4363923368509859).
  • Quindi prendiamo questo numero e convertiamo ad una stringa con base 16 (dall'esempio sopra otterremo 0.6fb7687f).
    Math.random().toString(16).
  • Quindi tagliamo il prefisso 0. (6fb7687f = > (Math.random().toString(16).substr(2,8)) e ottieni una stringa con otto esadecimali caratteri lunghi.
    0.4363.
  • A volte viene restituita la funzione 0.4363000000000000 numero più breve (ad esempio "000000000"), a causa di zeri alla fine (dall'esempio sopra, in realtà il numero è substr()). Ecco perché sto aggiungendo questa stringa "0"+"000000000" (una stringa con nove zeri) e quindi tagliandola con la funzione "1"+"000000000" per renderla esattamente nove caratteri (riempiendo gli zeri a destra).
  • Il motivo per aggiungere esattamente nove zeri è a causa dello scenario peggiore, ovvero quando la funzione Math.random().toString(16)+"000000000").substr(2,8) restituirà esattamente 0 o 1 (probabilità di 1/10 ^ 16 per ciascuno di essi). Ecco perché dovevamo aggiungere nove zeri (XXXXXXXX o -XXXX-XXXX) e quindi tagliarlo dal secondo indice (3 ° carattere) con una lunghezza di otto caratteri. Per il resto dei casi, l'aggiunta di zeri non danneggerà il risultato perché lo sta comunque tagliando.
    _p8(s).

L'assemblea:

  • Il GUID è nel seguente formato s.
  • Ho diviso il GUID in 4 pezzi, ogni pezzo diviso in 2 tipi (o formati): _p8() + _p8(true) + _p8(true) + _p8() e <=>.
  • Ora sto costruendo il GUID usando questi 2 tipi per assemblare il GUID con chiamate 4 pezzi, come segue: <=> <=> <=> <=>.
  • Per differenziare questi due tipi, ho aggiunto un parametro flag a una funzione creatore di coppia <=>, il parametro <=> indica alla funzione se aggiungere trattini o meno.
  • Alla fine costruiamo il GUID con il seguente concatenamento: <=> e lo restituiamo.

Link a questo post sul mio blog

Buon divertimento! : -)

Ecco una combinazione della risposta più votata , con una soluzione alternativa per Collisioni di Chrome :

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

Su jsbin se vuoi testarlo.

Ecco un'implementazione totalmente non conforme ma molto performante per generare un identificatore univoco simile a GUID ASCII-sicuro.

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

Genera 26 [a-z0-9] caratteri, producendo un UID più breve e più unico dei GUID conformi a RFC. I trattini possono essere aggiunti in modo banale se la leggibilità umana è importante.

Ecco esempi di utilizzo e tempi per questa funzione e molte altre risposte a questa domanda. I tempi sono stati eseguiti con Chrome m25, 10 milioni di iterazioni ciascuno.

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

Ecco il codice di temporizzazione.

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

Ecco una soluzione datata 9 ottobre 2011 da un commento dell'utente jed all'indirizzo 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)}

Questo raggiunge lo stesso obiettivo del l'attuale più alto risposta valutata , ma in oltre 50 byte in meno sfruttando la coercizione, la ricorsione e la notazione esponenziale. Per i curiosi su come funziona, ecco la forma annotata di una versione precedente della funzione:

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

Dal blog tecnico di 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;
}

Esistono altri metodi che prevedono l'utilizzo di un controllo ActiveX, ma state alla larga da questi!

Modifica: ho pensato che valesse la pena sottolineare che nessun generatore GUID può garantire chiavi univoche (controlla la articolo di Wikipedia ). C'è sempre la possibilità di collisioni. Un GUID offre semplicemente un universo di chiavi abbastanza grande da ridurre quasi a zero il cambiamento delle collisioni.

Puoi usare node-uuid ( https://github.com/kelektiv/node-uuid)

Generazione semplice e veloce di RFC4122 UUIDS.

Caratteristiche:

  • Genera UUID RFC4122 versione 1 o versione 4
  • Esegue in node.js e browser.
  • Generazione casuale casuale # crittograficamente su piattaforme di supporto.
  • Ingombro ridotto (vuoi qualcosa di più piccolo? Dai un'occhiata! )

Installa utilizzando NPM:

npm install uuid

O utilizzando uuid tramite browser:

Scarica il Raw File (uuid v1): https: // raw. githubusercontent.com/kelektiv/node-uuid/master/v1.js Scarica il Raw File (uuid v4): https://raw.githubusercontent.com /kelektiv/node-uuid/master/v4.js


Vuoi ancora più piccolo? Dai un'occhiata a: https://gist.github.com/jed/982883


Utilizzo:

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

Un servizio web sarebbe utile.

Ricerca rapida di Google: http://www.hoskinson.net/GuidGenerator/

Non posso garantire questa implementazione, ma QUALCUNO deve pubblicare un generatore GUID in buona fede.

Con un tale servizio Web, è possibile sviluppare un'interfaccia Web REST che utilizza il servizio Web GUID e lo serve tramite AJAX per javascript in un browser.

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

EDIT:

Rivisitato il mio progetto che utilizzava questa funzione e non mi piaceva la verbosità. - Ma avevo bisogno di una casualità adeguata.

Una versione basata sulla risposta di Briguy37 e alcuni operatori bit a bit per estrarre dal buffer finestre di dimensioni nibble.

Dovrebbe aderire allo schema RFC di Tipo 4 (casuale), poiché l'ultima volta ho avuto problemi durante l'analisi degli uuidi non conformi con l'UUID di Java.

Modulo JavaScript semplice come combinazione delle migliori risposte in questa discussione.

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

Utilizzo:

  
    

Guid.newGuid ()

         &

quot; c6c2d12f-d76b-5739-e551-07e6de5b0807 quot &;

         

Guid.empty

         

quot &; 00000000-0000-0000-0000-000000000000 quot &;

  

Da good ol 'wikipedia c'è un collegamento a un'implementazione javascript di UUID.

Sembra abbastanza elegante e potrebbe forse essere migliorato salando con un hash dell'indirizzo IP del client. Questo hash potrebbe forse essere inserito nel documento html lato server per essere utilizzato dal javascript lato client.

AGGIORNAMENTO: il sito originale ha subito un riordino, ecco il versione aggiornata

Bene, questo ha già un sacco di risposte, ma sfortunatamente non c'è un " true " casuale nel gruppo. La versione seguente è un adattamento della risposta di broofa, ma aggiornata per includere un & Quot; true & Quot; funzione casuale che utilizza le librerie di crittografia ove disponibili e la funzione Alea () come fallback.

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

Questo crea l'UUID versione 4 (creato da numeri pseudo casuali):

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

Ecco un esempio degli UUID generati:

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

Progetto JavaScript su GitHub - https://github.com/LiosK/UUID.js

  

UUID.js Il generatore UUID conforme a RFC per JavaScript.

     

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

     

Funzionalità Genera UUID conformi a RFC 4122.

     

UUID versione 4 (UUID da numeri casuali) e UUID versione 1   (UUID basati sul tempo) sono disponibili.

     

L'oggetto UUID consente una varietà di accesso all'UUID incluso l'accesso a   i campi UUID.

     

La bassa risoluzione data / ora di JavaScript è compensata da casuale   numeri.

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

Ho modificato il mio generatore UUID / GUID con alcuni extra qui .

Sto usando il seguente Kybos generatore di numeri casuali per essere un po 'più crittograficamente valido .

Di seguito è riportato il mio script con i metodi Mash e Kybos di baagoe.com esclusi.

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

Il modo migliore:

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
 }

minimizzato:

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}

Volevo capire la risposta di Broofa, quindi l'ho ampliata e ho aggiunto commenti:

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

Esempio ES6

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

È solo una semplice chiamata AJAX ...

Se qualcuno è ancora interessato, ecco la mia soluzione.

Sul lato server:

[WebMethod()]
public static string GenerateGuid()
{
    return Guid.NewGuid().ToString();
}

Sul lato client:

var myNewGuid = null;
PageMethods.GenerateGuid(
    function(result, userContext, methodName)
    {
        myNewGuid = result;
    },
    function()
    {
        alert("WebService call failed.");
    }
);

Per coloro che desiderano una soluzione conforme a rfc4122 versione 4 con considerazioni sulla velocità (poche chiamate a Math.random ()):

function UUID() {
    var nbr, randStr = "";
    do {
        randStr += (nbr = Math.random()).toString(16).substr(2);
    } 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)
        ].join("");
}

La funzione sopra dovrebbe avere un giusto equilibrio tra velocità e casualità.

Questo è basato sulla data e aggiungi un suffisso casuale a " assicurati " unicità. Funziona bene con identificatori CSS. Restituisce sempre qualcosa di simile ed è facile da hackerare:

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

Lo so, è una vecchia domanda. Per completezza, se l'ambiente è SharePoint, esiste una funzione di utilità chiamata SP.Guid.newGuid ( msdn link ) che crea un nuovo guid. Questa funzione si trova nel file sp.init.js. Se riscrivi questa funzione (per rimuovere alcune altre dipendenze da altre funzioni private), si presenta così:

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

Esiste un plug-in jQuery che gestisce piacevolmente Guid's @ http://plugins.jquery.com/project/ GUID_Helper

jQuery.Guid.Value()

Restituisce il valore della guida interna. Se non è stato specificato guid, ne restituisce uno nuovo (il valore viene quindi memorizzato internamente).


jQuery.Guid.New()

Restituisce un nuovo Guid e imposta il suo valore internamente.


jQuery.Guid.Empty()

Restituisce un Guid 00000000-0000-0000-0000-000000000000 vuoto.


jQuery.Guid.IsEmpty()

Restituisce il valore booleano. Vero se vuoto / non definito / vuoto / null.


jQuery.Guid.IsValid()

Restituisce il valore booleano. Vero guid valido, falso in caso contrario.


jQuery.Guid.Set()

Retrns Guid. Imposta Guid su Guid specificato dall'utente, se non valido, restituisce un guid vuoto.

Codice semplice che utilizza crypto.getRandomValues(a) su browser supportati (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Evita di usare Math.random() perché ciò può causare collisioni (ad esempio 20 collisioni per 4000 uuidi generati in una situazione reale di 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);
}

Note:

  • Ottimizzato per la leggibilità del codice e non per la velocità, quindi adatto per dire alcune centinaia di uuid al secondo. Genera circa 10000 uuid () al secondo in Chromium sul mio laptop usando http://jsbin.com/fuwigo/1 per misurare le prestazioni.
  • usa solo 8 per " y " perché ciò semplifica la leggibilità del codice (y può essere 8, 9, A o B).
Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top