Wie erstelle ich eine GUID / UUID?


4179

Ich versuche, global eindeutige Bezeichner in JavaScript zu erstellen. Ich bin mir nicht sicher, welche Routinen in allen Browsern verfügbar sind, wie "zufällig" und wie stark der integrierte Zufallszahlengenerator gesetzt ist usw.

Die GUID / UUID sollte mindestens 32 Zeichen lang sein und im ASCII-Bereich bleiben, um Probleme beim Weitergeben zu vermeiden.


13
GUIDs, die als Zeichenfolgen dargestellt werden, sind mindestens 36 und nicht länger als 38 Zeichen und entsprechen dem Muster ^ \ {? [A-zA-Z0-9] {36}? \} $ Und sind daher immer ASCII.
AnthonyWJones

2
David Bau bietet unter davidbau.com/archives/2010/01/30/ einen viel besseren, aussagekräftigen Zufallszahlengenerator. Ich habe einen etwas anderen Ansatz zum Generieren von UUIDs unter blogs.cozi.com/tech/2010/04/generating- geschrieben. uuids-in-javascript.html
George V. Reilly

Seltsam, dass dies noch niemand erwähnt hat, aber der Vollständigkeit halber gibt es auf npm eine Vielzahl von Guid-Generatoren. Ich bin bereit zu wetten, dass die meisten von ihnen auch im Browser funktionieren.
George Mauer

Antworten:


2339

UUIDs (Universally Unique IDentifier), auch als GUIDs (Globally Unique IDentifier) ​​bezeichnet, sind gemäß RFC 4122 Bezeichner, die bestimmte Eindeutigkeitsgarantien bieten sollen.

Während es möglich ist, RFC-kompatible UUIDs in einigen Zeilen von JS zu implementieren (siehe z. B. die Antwort von @ broofa unten), gibt es einige häufige Fallstricke:

  • Ungültiges ID-Format (UUIDs müssen die Form " xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx" haben, wobei x eine von [0-9, af] M eine von [1-5] und N [8, 9, a oder b] ist.
  • Verwendung von einer minderwertigen Zufallsquelle (wie zum Beispiel Math.random)

Entwickler, die Code für Produktionsumgebungen schreiben, werden daher aufgefordert, eine strenge, gut gewartete Implementierung wie das UUID- Modul zu verwenden.


186
Tatsächlich erlaubt der RFC UUIDs, die aus Zufallszahlen erstellt werden. Sie müssen nur ein paar Bits drehen, um es als solches zu identifizieren. Siehe Abschnitt 4.4. Algorithmen zum Erstellen einer UUID aus wirklich zufälligen oder pseudozufälligen
Jason DeFontes

Aufbauend auf allem in diesem Thread habe ich eine Version erstellt, die doppelt so schnell ist wie die unten stehende "e7" -Variante, kryptostark und auf allen gängigen Browsern und Knoten funktioniert. Es ist zu groß, um es hier aufzunehmen.
Suchen Sie

node-uuid ist jetzt uuid geworden (nach dem Zusammenführen mit dem letzteren Projekt)
Catweazle

4113

Für eine RFC4122- Version 4-kompatible Lösung ist diese Einzeiler -Lösung die kompakteste, die ich mir vorstellen kann :

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

Update, 02.06.2015 : Beachten Sie, dass die UUID-Eindeutigkeit stark vom zugrunde liegenden Zufallszahlengenerator (RNG) abhängt . Die Lösung obigen Verwendungen der Math.random()Kürze halber, jedoch Math.random()ist nicht gewährleistet eine qualitativ hochwertige RNG sein. Weitere Informationen finden Sie in Adam Hylands ausgezeichnetem Artikel über Math.random () . Für eine robustere Lösung sollten Sie das uuid-Modul verwenden , das RNG-APIs mit höherer Qualität verwendet.

Update, 26.08.2015 : Als Randnotiz wird beschrieben, wie ermittelt wird, wie viele IDs generiert werden können, bevor eine bestimmte Kollisionswahrscheinlichkeit erreicht wird. Mit 3.26x10 15 Version 4 RFC4122-UUIDs haben Sie beispielsweise eine Kollisionswahrscheinlichkeit von 1 zu 1 Million.

Update, 28.06.2017 : Ein guter Artikel von Chrome-Entwicklern zum Status von Math.random PRNG in Chrome, Firefox und Safari. tl; dr - Ab Ende 2015 ist es "ziemlich gut", aber keine kryptografische Qualität. Um dieses Problem zu beheben, finden Sie hier eine aktualisierte Version der oben genannten Lösung, die ES6, die cryptoAPI und ein wenig JS-Assistenten verwendet, für die ich keine Anerkennung finden kann :

function uuidv4() {
  return ([1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  );
}

console.log(uuidv4());

Update, 06.01.2020 : In Arbeit ist ein Vorschlag für ein Standardmodul uuidals Teil der JS-Sprache


30
Ich habe eine Frage zu Kollisionen gestapelt stackoverflow.com/questions/6906916/…
Muxa

4
@marc - Die Qualität von Math.random () ist ein Problem. Ohne eine detaillierte Analyse der zugrunde liegenden Implementierung, die mit ziemlicher Sicherheit den x-Browser variiert, können wir die tatsächlichen Kollisionswahrscheinlichkeiten nicht kennen. Der Einfachheit halber gehe ich von einer idealen Quelle der Zufälligkeit aus. Aber ja, das kann eine gefährliche Annahme sein, wie das Thema von Muxa hervorhebt. Aus diesem Grund bevorzuge ich in node-uuid ( github.com/broofa/node-uuid ) andere APIs, die Zufälligkeit in kryptografischer Qualität gegenüber Math.random () garantieren, obwohl die Leistung darunter leidet.
Broofa

144
Sicherlich lautet die Antwort auf @ Muxas Frage "Nein"? Es ist nie wirklich sicher, etwas zu vertrauen, das vom Kunden stammt. Ich denke, es hängt davon ab, wie wahrscheinlich es ist, dass Ihre Benutzer eine Javascript-Konsole aufrufen und die Variable manuell so ändern, wie sie es möchten. Oder sie können Ihnen einfach die ID zurückschicken, die sie möchten. Dies hängt auch davon ab, ob der Benutzer, der seine eigene ID auswählt, Schwachstellen verursacht. Wenn es sich um eine Zufallszahlen-ID handelt, die in eine Tabelle aufgenommen wird, würde ich sie wahrscheinlich serverseitig generieren, damit ich weiß, dass ich die Kontrolle über den Prozess habe.
Cam Jackson

36
@DrewNoakes - UUIDs sind nicht nur eine Folge von völlig zufälligen #. Die "4" ist die UUID-Version (4 = "zufällig"). Das "y" markiert, wo die UUID-Variante (Feldlayout im Grunde) eingebettet werden muss. Weitere Informationen finden Sie in den Abschnitten 4.1.1 und 4.1.3 von ietf.org/rfc/rfc4122.txt .
Broofa

5
warum c== 'x'statt c === 'x'. Weil jshint fehlgeschlagen ist.
Fizer Khan

810

Ich mag es wirklich, wie sauber Broofas Antwort ist, aber es ist bedauerlich, dass schlechte ImplementierungenMath.random die Chance auf eine Kollision lassen.

Hier ist eine ähnliche RFC4122- Version 4-kompatible Lösung, die dieses Problem löst, indem die ersten 13 Hex-Zahlen um einen hexadezimalen Teil des Zeitstempels und einmal versetzte Offsets um einen hexadezimalen Teil der Mikrosekunden seit dem Laden der Seite versetzt werden. Auf diese Weise Math.randommüssten beide Clients , selbst wenn sie sich auf demselben Startwert befinden, die UUID genau die gleiche Anzahl von Mikrosekunden seit dem Seitenladen (wenn eine Zeit mit hoher Leistung unterstützt wird) UND genau dieselbe Millisekunde (oder mehr als 10.000 Jahre später) generieren Holen Sie sich die gleiche UUID:

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();//Timestamp
    var d2 = (performance && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        var r = Math.random() * 16;//random number between 0 and 16
        if(d > 0){//Use timestamp until depleted
            r = (d + r)%16 | 0;
            d = Math.floor(d/16);
        } else {//Use microseconds since page-load if supported
            r = (d2 + r)%16 | 0;
            d2 = Math.floor(d2/16);
        }
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}

console.log(generateUUID())


Hier ist eine Geige zum Testen.


31
Beachten Sie, dass new Date().getTime()nicht jede Millisekunde aktualisiert wird. Ich bin nicht sicher, wie sich dies auf die erwartete Zufälligkeit Ihres Algorithmus auswirkt.
devios1

84
Leistung. Jetzt wäre noch besser. Im Gegensatz zu Date.now sind die von zurückgegebenen Zeitstempel performance.now()nicht auf eine Auflösung von einer Millisekunde beschränkt. Stattdessen stellen sie Zeiten als Gleitkommazahlen mit einer Genauigkeit von bis zu Mikrosekunden dar . Im Gegensatz zu Date.now steigen die von performance.now () zurückgegebenen Werte unabhängig von der Systemuhr, die möglicherweise manuell angepasst oder durch Software wie das Network Time Protocol verzerrt wird, immer mit einer konstanten Rate an .
Daniellmb

6
@daniellmb Sie sollten wahrscheinlich mit MDN oder einem anderen verlinkt haben, um echte Dokumentation und keine Polyfüllung zu zeigen;)
Martin

2
Darf ich wissen, wofür die Rundung verwendet wird d = Math.floor(d/16);?
Praveen

2
@Praveen Durch diese Operation wird der Zeitstempel um eine hexadezimale Ziffer nach rechts verschoben und der Rest wird gelöscht. Ihr Zweck ist es, die gerade verwendete Hex-Ziffer (die niedrigstwertige) zu entfernen und für die nächste Iteration vorzubereiten.
Briguy37

431

Die Antwort von broofa ist in der Tat ziemlich raffiniert - beeindruckend clever, wirklich ... rfc4122-konform, etwas lesbar und kompakt. Genial!

Wenn Sie sich jedoch diesen regulären Ausdruck, diese vielen replace()Rückrufe, Funktionsaufrufe toString()und Math.random()Funktionsaufrufe ansehen (bei denen er nur 4 Bits des Ergebnisses verwendet und den Rest verschwendet), werden Sie sich möglicherweise über die Leistung wundern. In der Tat hat Joelpt sogar beschlossen, RFC für die generische GUID-Geschwindigkeit mit wegzuwerfen generateQuickGUID.

Aber können wir Geschwindigkeit und RFC-Konformität erreichen? Ich sage ja! Können wir die Lesbarkeit aufrechterhalten? Nun ... Nicht wirklich, aber es ist einfach, wenn Sie mitmachen.

Aber zuerst meine Ergebnisse im Vergleich zu Broofa guid(die akzeptierte Antwort) und die nicht rfc-konformen 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.

Also von meiner sechsten Iteration von Optimierungen, schlug ich die populärste Antwort von über 12X , die akzeptierte Antwort von über 9X und die schnell nicht konforme Antwort von 2-3X . Und ich bin immer noch rfc4122-konform.

Interessiert wie? Ich habe die vollständige Quelle auf http://jsfiddle.net/jcward/7hyaC/3/ und auf http://jsperf.com/uuid-generator-opt/4 veröffentlicht

Beginnen wir zur Erklärung mit dem Code von broofa:

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

console.log(broofa())

Es wird also xdurch eine zufällige hexadezimale Ziffer ymit zufälligen Daten ersetzt (außer dass die obersten 2 Bits 10gemäß der RFC-Spezifikation erzwungen werden), und der reguläre Ausdruck stimmt nicht mit den Zeichen -oder überein 4, sodass er sich nicht mit ihnen befassen muss. Sehr, sehr glatt.

Das Erste, was man wissen muss, ist, dass Funktionsaufrufe teuer sind, ebenso wie reguläre Ausdrücke (obwohl er nur 1 verwendet, hat er 32 Rückrufe, einen für jede Übereinstimmung, und in jedem der 32 Rückrufe ruft er Math.random () und v auf. toString (16)).

Der erste Schritt in Richtung Leistung besteht darin, den RegEx und seine Rückruffunktionen zu entfernen und stattdessen eine einfache Schleife zu verwenden. Dies bedeutet, dass wir uns mit den Zeichen -und befassen müssen, 4während Broofa dies nicht tat. Beachten Sie auch, dass wir die String-Array-Indizierung verwenden können, um seine raffinierte String-Vorlagenarchitektur beizubehalten:

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

console.log(e1())

Grundsätzlich führt dieselbe innere Logik, außer dass wir nach -oder suchen 4und eine while-Schleife (anstelle von replace()Rückrufen) verwenden, zu einer fast dreifachen Verbesserung!

Der nächste Schritt ist ein kleiner auf dem Desktop, macht aber auf Mobilgeräten einen ordentlichen Unterschied. Lassen Sie uns weniger Math.random () -Aufrufe durchführen und all diese zufälligen Bits verwenden, anstatt 87% davon mit einem zufälligen Puffer wegzuwerfen, der bei jeder Iteration verschoben wird. Verschieben wir auch diese Vorlagendefinition aus der Schleife, nur für den Fall, dass es hilft:

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

console.log(e2())

Dies spart uns je nach Plattform 10-30%. Nicht schlecht. Aber der nächste große Schritt beseitigt die Funktionsaufrufe von toString mit einem Optimierungsklassiker - der Nachschlagetabelle. Eine einfache Nachschlagetabelle mit 16 Elementen erledigt die Aufgabe von toString (16) in viel kürzerer Zeit:

function e3() {
    var h='0123456789abcdef';
    var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';
    /* same as e4() below */
}
function e4() {
    var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];
    var k=['x','x','x','x','x','x','x','x','-','x','x','x','x','-','4','x','x','x','-','y','x','x','x','-','x','x','x','x','x','x','x','x','x','x','x','x'];
    var u='',i=0,rb=Math.random()*0xffffffff|0;
    while(i++<36) {
        var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);
        u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4
    }
    return u
}

console.log(e4())

Die nächste Optimierung ist ein weiterer Klassiker. Da wir in jeder Schleifeniteration nur 4-Bit-Ausgabe verarbeiten, halbieren wir die Anzahl der Schleifen und verarbeiten jede Iteration 8-Bit. Dies ist schwierig, da wir immer noch mit den RFC-kompatiblen Bitpositionen umgehen müssen, aber es ist nicht zu schwierig. Wir müssen dann eine größere Nachschlagetabelle (16x16 oder 256) erstellen, um 0x00 - 0xff zu speichern, und wir erstellen sie nur einmal außerhalb der Funktion e5 ().

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

console.log(e5())

Ich habe ein e6 () ausprobiert, das jeweils 16 Bit verarbeitet und dabei immer noch die 256-Elemente-LUT verwendet, und es hat die abnehmenden Optimierungsrenditen gezeigt. Obwohl es weniger Iterationen gab, wurde die innere Logik durch die erhöhte Verarbeitung kompliziert, und es lief auf dem Desktop genauso und auf Mobilgeräten nur ~ 10% schneller.

Die letzte anzuwendende Optimierungstechnik - Rollen Sie die Schleife ab. Da wir eine feste Anzahl von Schleifen durchlaufen, können wir dies alles technisch von Hand ausschreiben. Ich habe dies einmal mit einer einzelnen Zufallsvariablen r versucht, die ich immer wieder neu zugewiesen habe, und die Leistung wurde gesteigert. Da jedoch vier Variablen im Voraus zufällige Daten zugewiesen wurden, dann die Nachschlagetabelle verwendet und die richtigen RFC-Bits angewendet wurden, raucht diese Version alle:

var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }
function e7()
{
    var d0 = Math.random()*0xffffffff|0;
    var d1 = Math.random()*0xffffffff|0;
    var d2 = Math.random()*0xffffffff|0;
    var d3 = Math.random()*0xffffffff|0;
    return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+
    lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+
    lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+
    lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];
}

console.log(e7())

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

Das Lustige ist, 16 Bytes zufälliger Daten zu generieren, ist der einfache Teil. Der ganze Trick besteht darin, es im String-Format mit RFC-Konformität auszudrücken, und es wird am besten mit 16 Bytes zufälliger Daten, einer nicht gerollten Schleife und einer Nachschlagetabelle erreicht.

Ich hoffe, meine Logik ist richtig - es ist sehr leicht, bei dieser Art von mühsamer Arbeit einen Fehler zu machen. Aber die Ausgänge sehen für mich gut aus. Ich hoffe, Sie haben diese tolle Fahrt durch die Codeoptimierung genossen!

Seien Sie gewarnt: Mein primäres Ziel war es, mögliche Optimierungsstrategien aufzuzeigen und zu vermitteln. Andere Antworten behandeln wichtige Themen wie Kollisionen und echte Zufallszahlen, die für die Generierung guter UUIDs wichtig sind.


14
Dieser Code enthält immer noch ein paar Fehler: Die Math.random()*0xFFFFFFFFZeilen sollten Math.random()*0x100000000vollständig zufällig sein und >>>0stattdessen verwendet werden |0, um die Werte nicht signiert zu halten (obwohl ich denke, dass sie mit dem aktuellen Code in Ordnung sind, obwohl sie signiert sind). Schließlich wäre es heutzutage eine sehr gute Idee, diese zu verwenden, window.crypto.getRandomValuesfalls verfügbar, und nur dann auf Math.random zurückzugreifen, wenn dies unbedingt erforderlich ist. Math.random kann durchaus weniger als 128 Entropiebits aufweisen. In diesem Fall wäre dies anfälliger für Kollisionen als erforderlich.
Dave

Aufbauend auf allem, was bereits in diesem Thread enthalten ist, habe ich etwas doppelt so schnell wie "e7" erstellt, alle Umgebungen einschließlich des Knotens portierbar gemacht und von Math.random () auf Zufälligkeit mit Kryptostärke aktualisiert. Sie denken vielleicht nicht, dass uuid Kryptostärke benötigt, aber das bedeutet, dass die Wahrscheinlichkeit einer Kollision noch geringer ist, was den gesamten Punkt einer uuid ausmacht. Zu groß, um in einen Kommentar zu passen, habe ich separat veröffentlicht.
Bennett Barouch

164

Hier ist ein Code, der auf RFC 4122 basiert , Abschnitt 4.4 (Algorithmen zum Erstellen einer UUID aus einer wirklich zufälligen oder pseudozufälligen Zahl).

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

    var uuid = s.join("");
    return uuid;
}

4
Sie sollten die Arraygröße im Voraus deklarieren, anstatt sie beim Erstellen der GUID dynamisch zu dimensionieren. var s = new Array(36);
MgSam

1
Ich denke, es gibt einen sehr kleinen Fehler in der Zeile, der die Bits 6-7 von clock_seq_hi_and_reserved auf 01 setzt. Da s [19] ein Zeichen '0' .. 'f' und kein int 0x0..0xf ist, (s [19] & 0x3) | 0x8 wird nicht zufällig verteilt - es werden tendenziell mehr '9' und weniger 'b' erzeugt. Dies macht nur dann einen Unterschied, wenn Sie sich aus irgendeinem Grund für die zufällige Verteilung interessieren.
John Velonis

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

Wenn IDs im Abstand von mehr als 1 Millisekunde generiert werden, sind sie zu 100% eindeutig.

Wenn zwei IDs in kürzeren Intervallen generiert werden und davon ausgegangen wird, dass die Zufallsmethode wirklich zufällig ist, werden IDs generiert, die zu 99,99999999999999% wahrscheinlich global eindeutig sind (Kollision in 1 von 10 ^ 15).

Sie können diese Zahl erhöhen, indem Sie weitere Ziffern hinzufügen. Um jedoch 100% eindeutige IDs zu generieren, müssen Sie einen globalen Zähler verwenden.

Wenn Sie RFC-Kompatibilität benötigen, wird diese Formatierung als gültige GUID der Version 4 übergeben:

let u = Date.now().toString(16) + Math.random().toString(16) + '0'.repeat(16);
let guid = [u.substr(0,8), u.substr(8,4), '4000-8' + u.substr(13,3), u.substr(16,12)].join('-');

Bearbeiten: Der obige Code folgt der Absicht, aber nicht dem Buchstaben des RFC. Unter anderem sind einige zufällige Ziffern kurz. (Fügen Sie bei Bedarf weitere zufällige Ziffern hinzu.) Der Vorteil ist, dass dies sehr schnell geht :) Hier können Sie die Gültigkeit Ihrer GUID testen


4
Dies ist jedoch keine UUID?
Marco Kerwitz

Nein. UUID / GUIDs sind eine 122-Bit-Nummer (+ sechs reservierte Bits). Es kann die Eindeutigkeit durch einen globalen Zählerservice garantieren, hängt jedoch häufig von Zeit, MAC-Adresse und Zufälligkeit ab. UUIDs sind nicht zufällig! Die hier vorgeschlagene UID ist nicht vollständig komprimiert. Sie können es auf eine 122-Bit-Ganzzahl komprimieren, die 6 vordefinierten Bits und zusätzlichen Zufallsbits hinzufügen (einige Timer-Bits entfernen) und Sie erhalten eine perfekt geformte UUID / GUID, die Sie dann in hex konvertieren müssten. Für mich bedeutet das nichts anderes als die Einhaltung der Länge der ID.
Simon Rigét

5
Es ist eine schlechte Idee, MAC-Adressen für die Eindeutigkeit auf virtuellen Maschinen weiterzuleiten!
Simon Rigét

1
Ich mache so etwas, aber mit Hauptfiguren und einigen Bindestrichen (z . B. [slug, date, random].join("_")zum Erstellen usr_1dcn27itd_hj6onj6phr. Dadurch wird die ID auch als "Erstellt am" -Feld verwendet
Seph Reed,

95

Schnellste GUID-ähnliche String-Generator-Methode im Format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. Dies generiert keine standardkonforme GUID.

Zehn Millionen Ausführungen dieser Implementierung dauern nur 32,5 Sekunden. Dies ist die schnellste, die ich je in einem Browser gesehen habe (die einzige Lösung ohne Schleifen / Iterationen).

Die Funktion ist so einfach wie:

/**
 * Generates a GUID string.
 * @returns {string} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser.
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

Um die Leistung zu testen, können Sie diesen Code ausführen:

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

Ich bin sicher, die meisten von Ihnen werden verstehen, was ich dort getan habe, aber vielleicht gibt es mindestens eine Person, die eine Erklärung benötigt:

Der Algorithmus:

  • Die Math.random()Funktion gibt eine Dezimalzahl zwischen 0 und 1 mit 16 Stellen nach dem Dezimalbruchpunkt zurück (zum Beispiel 0.4363923368509859).
  • Dann nehmen wir diese Zahl und konvertieren sie in eine Zeichenfolge mit Basis 16 (aus dem obigen Beispiel erhalten wir 0.6fb7687f).
    Math.random().toString(16).
  • Dann schneiden wir das 0.Präfix ( 0.6fb7687f=> 6fb7687f) ab und erhalten eine Zeichenfolge mit acht hexadezimalen Zeichen.
    (Math.random().toString(16).substr(2,8).
  • Manchmal gibt die Math.random()Funktion 0.4363aufgrund von Nullen am Ende eine kürzere Zahl zurück (zum Beispiel ) (aus dem obigen Beispiel ist die Zahl tatsächlich 0.4363000000000000). Deshalb füge ich diese Zeichenfolge hinzu "000000000"(eine Zeichenfolge mit neun Nullen) und schneide sie dann mit der substr()Funktion ab, um sie genau auf neun Zeichen zu setzen (wobei Nullen rechts ausgefüllt werden).
  • Der Grund für das Hinzufügen von genau neun Nullen ist das Worst-Case-Szenario, bei dem die Math.random()Funktion genau 0 oder 1 zurückgibt (Wahrscheinlichkeit von 1/10 ^ 16 für jede von ihnen). Deshalb mussten wir neun Nullen hinzufügen ( "0"+"000000000"oder "1"+"000000000") und es dann mit einer Länge von acht Zeichen vom zweiten Index (3. Zeichen) abschneiden. In den übrigen Fällen schadet das Hinzufügen von Nullen dem Ergebnis nicht, da es ohnehin abgeschnitten wird.
    Math.random().toString(16)+"000000000").substr(2,8).

Die Versammlung:

  • Die GUID hat das folgende Format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • Ich habe die GUID in 4 Teile unterteilt, wobei jedes Teil in zwei Typen (oder Formate) unterteilt ist: XXXXXXXXund -XXXX-XXXX.
  • Jetzt erstelle ich die GUID mit diesen beiden Typen, um die GUID mit Call 4-Teilen wie folgt zusammenzusetzen : XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Um zwischen diesen beiden Typen zu unterscheiden, habe ich einer Paarerstellungsfunktion einen Flag-Parameter hinzugefügt. _p8(s)Der sParameter teilt der Funktion mit, ob Bindestriche hinzugefügt werden sollen oder nicht.
  • Schließlich erstellen wir die GUID mit der folgenden Verkettung: _p8() + _p8(true) + _p8(true) + _p8()und geben sie zurück.

Link zu diesem Beitrag in meinem Blog

Genießen! :-)


13
Diese Implementierung ist falsch. Bestimmte Zeichen der GUID erfordern eine besondere Behandlung (z. B. muss die 13. Ziffer die Nummer 4 sein).
JLRishe

67

Hier ist eine Kombination der am häufigsten bewerteten Antwort mit einer Problemumgehung für die Kollisionen von Chrome :

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // /programming/6906916/collisions-when-generating-uuids-in-javascript
        var buf = new Uint16Array(8);
        window.crypto.getRandomValues(buf);
        var S4 = function(num) {
            var ret = num.toString(16);
            while(ret.length < 4){
                ret = "0"+ret;
            }
            return ret;
        };
        return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
    }

    :

    function() {
        // Otherwise, just use Math.random
        // /programming/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
            return v.toString(16);
        });
    };

Auf jsbin, wenn Sie es testen möchten.


3
Beachten Sie, dass die erste Version, die "window.crypto.getRandomValues , does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxxx", die sie liefert xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx.
Menschheit und

66

Hier ist eine völlig nicht konforme, aber sehr leistungsfähige Implementierung zum Generieren einer ASCII-sicheren GUID-ähnlichen eindeutigen Kennung.

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

Generiert 26 [a-z0-9] Zeichen und ergibt eine UID, die sowohl kürzer als auch eindeutiger als RFC-kompatible GUIDs ist. Striche können trivial hinzugefügt werden, wenn die Lesbarkeit wichtig ist.

Hier finden Sie Anwendungsbeispiele und Timings für diese Funktion sowie einige der anderen Antworten dieser Frage. Das Timing wurde unter Chrome m25 mit jeweils 10 Millionen Iterationen durchgeführt.

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

Hier ist der Timing-Code.

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

62

Hier ist eine Lösung vom 9. Oktober 2011 aus einem Kommentar des Benutzers jed unter 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)}

Dies erreicht das gleiche Ziel wie die derzeit am höchsten bewertete Antwort , jedoch in mehr als 50 Bytes weniger, indem Zwang, Rekursion und Exponentialschreibweise ausgenutzt werden. Für diejenigen, die neugierig sind, wie es funktioniert, hier die kommentierte Form einer älteren Version der Funktion:

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

Aus dem technischen Blog von 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;
}

Es gibt andere Methoden, bei denen ein ActiveX-Steuerelement verwendet wird. Halten Sie sich jedoch von diesen fern!

Bearbeiten: Ich dachte, es lohnt sich darauf hinzuweisen, dass kein GUID-Generator eindeutige Schlüssel garantieren kann (siehe Wikipedia-Artikel ). Es besteht immer die Möglichkeit von Kollisionen. Eine GUID bietet einfach ein ausreichend großes Universum an Schlüsseln, um die Änderung von Kollisionen auf fast Null zu reduzieren.


8
Beachten Sie, dass dies keine GUID im technischen Sinne ist, da sie nichts zur Gewährleistung der Eindeutigkeit beiträgt. Das kann je nach Ihrer Anwendung von Bedeutung sein oder auch nicht.
Stephen Deken

2
Ein kurzer Hinweis zur Leistung. Diese Lösung erstellt insgesamt 36 Zeichenfolgen, um ein einzelnes Ergebnis zu erhalten. Wenn die Leistung kritisch ist, sollten Sie ein Array erstellen und beitreten, wie von: tinyurl.com/y37xtx empfohlen. Weitere Untersuchungen haben ergeben, dass dies möglicherweise keine Rolle spielt. YMMV: tinyurl.com/3l7945
Brandon DuRette

2
In Bezug auf die Eindeutigkeit ist anzumerken, dass die UUIDs der Versionen 1,3 und 5 in einer Weise deterministisch sind, wie dies in Version 4 nicht der Fall ist. Wenn die Eingaben für diese UUID-Generatoren - Knoten-ID in Version 1, Namespace und Name in Version 3 und Version 5 - eindeutig sind (wie sie sein sollen), sind die resultierenden UUIDs eindeutig. Theoretisch jedenfalls.
Broofa

41

Sie können node-uuid verwenden ( https://github.com/kelektiv/node-uuid )

Einfache und schnelle Generierung von RFC4122- UUIDS.

Eigenschaften:

  • Generieren Sie RFC4122-UUIDs der Version 1 oder 4
  • Läuft in node.js und Browsern.
  • Kryptografisch starke zufällige # Generierung auf unterstützenden Plattformen.
  • Kleiner Platzbedarf (Möchten Sie etwas Kleineres? Schauen Sie sich das an! )

Installation mit NPM:

npm install uuid

Oder Verwenden von uuid über einen Browser:

Raw-Datei herunterladen (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Raw-Datei herunterladen (uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid / master / v4.js.


Willst du noch kleiner? Überprüfen Sie dies: https://gist.github.com/jed/982883


Verwendungszweck:

// Generate a v1 UUID (time-based)
const uuidV1 = require('uuid/v1');
uuidV1(); // -> '6c84fb90-12c4-11e1-840d-7b25c5ee775a'

// Generate a v4 UUID (random)
const uuidV4 = require('uuid/v4');
uuidV4(); // -> '110ec58a-a0f2-4ac4-8393-c866d813b8d1'

// Generate a v5 UUID (namespace)
const uuidV5 = require('uuid/v5');

// ... using predefined DNS namespace (for domain names)
uuidV5('hello.example.com', v5.DNS)); // -> 'fdda765f-fc57-5604-a269-52a7df8164ec'

// ... using predefined URL namespace (for, well, URLs)
uuidV5('http://example.com/hello', v5.URL); // -> '3bbcee75-cecc-5b56-8031-b6641c1ed1f1'

// ... using a custom namespace
const MY_NAMESPACE = '(previously generated unique uuid string)';
uuidV5('hello', MY_NAMESPACE); // -> '90123e1c-7512-523e-bb28-76fab9f2f73d'

ES6:

import uuid from 'uuid/v4';
const id = uuid();

34
var uuid = function() {
    var buf = new Uint32Array(4);
    window.crypto.getRandomValues(buf);
    var idx = -1;
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
        idx++;
        var r = (buf[idx>>3] >> ((idx%8)*4))&15;
        var v = c == 'x' ? r : (r&0x3|0x8);
        return v.toString(16);
    });
};

BEARBEITEN:

Ich habe mein Projekt, das diese Funktion verwendete, erneut besucht und die Ausführlichkeit nicht gemocht. - Aber brauchte richtige Zufälligkeit.

Eine Version, die auf der Antwort von Briguy37 und einigen bitweisen Operatoren basiert, um Fenster in Nibble-Größe aus dem Puffer zu extrahieren.

Sollte sich an das (zufällige) RFC-Typ-4-Schema halten, da ich beim letzten Mal Probleme hatte, nicht konforme UUids mit Javas UUID zu analysieren.


31

Einfaches JavaScript-Modul als Kombination der besten Antworten in diesem Thread.

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

Verwendungszweck:

Guid.newGuid ()

c6c2d12f-d76b-5739-e551-07e6de5b0807

Guid.empty

"00000000-0000-0000-0000-000000000000"


1
Was weiß man über stört alle Antworten ist , dass es scheint ok für JavaScript , um die zu speichern GUIDals string. Ihre Antwort befasst sich zumindest mit der viel effizienteren Speicherung mit a Uint16Array. Die toStringFunktion sollte die binäre Darstellung in einem JavaScript verwendenobject
Sebastian

Diese von diesem Code erzeugten UUIDs sind entweder schwach, aber RFC-kompatibel (_guid) oder stark, aber nicht RFC-kompatibel (_cryptoGuid). Ersteres verwendet Math.random (), das jetzt als schlechtes RNG bekannt ist. Letzteres kann die Versions- und Variantenfelder nicht festlegen.
Broofa

@broofa - Was würden Sie vorschlagen, um es stark und RFC-konform zu machen? Und warum ist _cryptoGuid nicht RFC-kompatibel?
Matt

@Matt _cryptoGuid () setzt alle 128 Bits zufällig, was bedeutet, dass die Versions- und Variantenfelder nicht wie im RFC beschrieben gesetzt werden. Siehe meine alternative Implementierung von uuidv4 (), die crypto.getRandomValues ​​() verwendet, in meiner Antwort mit der höchsten Bewertung oben für eine starke + konforme Implementierung.
Broofa

29

Diese UUID der Version 4 (erstellt aus Pseudozufallszahlen):

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

Hier ist ein Beispiel der generierten UUIDs:

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

28

Nun, dies hat bereits eine Reihe von Antworten, aber leider gibt es keinen "wahren" Zufall in der Reihe. Die folgende Version ist eine Anpassung der Antwort von broofa, wurde jedoch aktualisiert und enthält nun eine "echte" Zufallsfunktion, die Kryptobibliotheken verwendet, sofern verfügbar, und die Alea () -Funktion als 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 https://web.archive.org/web/20120502223108/http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <baagoe@baagoe.com>, 2010
      function Mash() {
          var n = 0xefc8249d;

          var mash = function(data) {
              data = data.toString();
              for (var i = 0; i < data.length; i++) {
                  n += data.charCodeAt(i);
                  var h = 0.02519603282416938 * n;
                  n = h >>> 0;
                  h -= n;
                  h *= n;
                  n = h >>> 0;
                  h -= n;
                  n += h * 0x100000000; // 2^32
              }
              return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
          };

          mash.version = 'Mash 0.9';
          return mash;
      }

      // From http://baagoe.com/en/RandomMusings/javascript/
      function Alea() {
          return (function(args) {
              // Johannes Baagøe <baagoe@baagoe.com>, 2010
              var s0 = 0;
              var s1 = 0;
              var s2 = 0;
              var c = 1;

              if (args.length == 0) {
                  args = [+new Date()];
              }
              var mash = Mash();
              s0 = mash(' ');
              s1 = mash(' ');
              s2 = mash(' ');

              for (var i = 0; i < args.length; i++) {
                  s0 -= mash(args[i]);
                  if (s0 < 0) {
                      s0 += 1;
                  }
                  s1 -= mash(args[i]);
                  if (s1 < 0) {
                      s1 += 1;
                  }
                  s2 -= mash(args[i]);
                  if (s2 < 0) {
                      s2 += 1;
                  }
              }
              mash = null;

              var random = function() {
                  var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                  s0 = s1;
                  s1 = s2;
                  return s2 = t - (c = t | 0);
              };
              random.uint32 = function() {
                  return random() * 0x100000000; // 2^32
              };
              random.fract53 = function() {
                  return random() +
                      (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
              };
              random.version = 'Alea 0.9';
              random.args = args;
              return random;

          }(Array.prototype.slice.call(arguments)));
      };
      return Alea();
  }
}());

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

27

JavaScript-Projekt auf GitHub - https://github.com/LiosK/UUID.js

UUID.js Der RFC-kompatible UUID-Generator für JavaScript.

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

Funktionen Erzeugt RFC 4122-kompatible UUIDs.

UUIDs der Version 4 (UUIDs aus Zufallszahlen) und UUIDs der Version 1 (zeitbasierte UUIDs) sind verfügbar.

Das UUID-Objekt ermöglicht eine Vielzahl von Zugriffen auf die UUID, einschließlich des Zugriffs auf die UUID-Felder.

Eine niedrige Zeitstempelauflösung von JavaScript wird durch Zufallszahlen kompensiert.


21
  // RFC 4122
  //
  // A UUID is 128 bits long
  //
  // String representation is five fields of 4, 2, 2, 2, and 6 bytes.
  // Fields represented as lowercase, zero-filled, hexadecimal strings, and
  // are separated by dash characters
  //
  // A version 4 UUID is generated by setting all but six bits to randomly
  // chosen values
  var uuid = [
    Math.random().toString(16).slice(2, 10),
    Math.random().toString(16).slice(2, 6),

    // Set the four most significant bits (bits 12 through 15) of the
    // time_hi_and_version field to the 4-bit version number from Section
    // 4.1.3
    (Math.random() * .0625 /* 0x.1 */ + .25 /* 0x.4 */).toString(16).slice(2, 6),

    // Set the two most significant bits (bits 6 and 7) of the
    // clock_seq_hi_and_reserved to zero and one, respectively
    (Math.random() * .25 /* 0x.4 */ + .5 /* 0x.8 */).toString(16).slice(2, 6),

    Math.random().toString(16).slice(2, 14)].join('-');

16

Ich wollte die Antwort von broofa verstehen, also habe ich sie erweitert und Kommentare hinzugefügt:

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

Vielen Dank für die ausführliche Beschreibung! Speziell Knabbereien zwischen 8 und 11 mit entsprechenden Erklärungen sind sehr hilfreich.
Egor Litvinchuk

15

Ich habe meinen eigenen UUID / GUID-Generator mit einigen Extras hier angepasst .

Ich benutze die folgenden Kybos Zufallszahlengenerator, um ein bisschen kryptografischer zu sein.

Unten ist mein Skript mit den Mash- und Kybos-Methoden von baagoe.com ausgeschlossen.

//UUID/Guid Generator
// use: UUID.create() or UUID.createSequential()
// convenience:  UUID.empty, UUID.tryParse(string)
(function(w){
  // From http://baagoe.com/en/RandomMusings/javascript/
  // Johannes Baagøe <baagoe@baagoe.com>, 2010
  //function Mash() {...};

  // From http://baagoe.com/en/RandomMusings/javascript/
  //function Kybos() {...};

  var rnd = Kybos();

  //UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
  var UUID = {
    "empty": "00000000-0000-0000-0000-000000000000"
    ,"parse": function(input) {
      var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
      if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
        return ret;
      else
        throw new Error("Unable to parse UUID");
    }
    ,"createSequential": function() {
      var ret = new Date().valueOf().toString(16).replace("-","")
      for (;ret.length < 12; ret = "0" + ret);
      ret = ret.substr(ret.length-12,12); //only least significant part
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"create": function() {
      var ret = "";
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"random": function() {
      return rnd();
    }
    ,"tryParse": function(input) {
      try {
        return UUID.parse(input);
      } catch(ex) {
        return UUID.empty;
      }
    }
  };
  UUID["new"] = UUID.create;

  w.UUID = w.Guid = UUID;
}(window || this));

15

Für diejenigen, die eine rfc4122 Version 4-kompatible Lösung mit Geschwindigkeitsüberlegungen wünschen (wenige Aufrufe von Math.random ()):

var rand = Math.random;

function UUID() {
    var nbr, randStr = "";
    do {
        randStr += (nbr = rand()).toString(16).substr(3, 6);
    } while (randStr.length < 30);
    return (
        randStr.substr(0, 8) + "-" +
        randStr.substr(8, 4) + "-4" +
        randStr.substr(12, 3) + "-" +
        ((nbr*4|0)+8).toString(16) + // [89ab]
        randStr.substr(15, 3) + "-" +
        randStr.substr(18, 12)
    );
}

console.log( UUID() );

Die obige Funktion sollte ein angemessenes Gleichgewicht zwischen Geschwindigkeit und Zufälligkeit aufweisen.


13

ES6-Probe

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

12

Der bessere Weg:

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
 }

Minimiert:

function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}

11

Ich weiß, es ist eine alte Frage. Der Vollständigkeit halber gibt es, wenn Ihre Umgebung SharePoint ist, eine Dienstprogrammfunktion namens SP.Guid.newGuid( msdn link ), die eine neue Guid erstellt. Diese Funktion befindet sich in der Datei sp.init.js. Wenn Sie diese Funktion neu schreiben (um einige andere Abhängigkeiten von anderen privaten Funktionen zu entfernen), sieht sie folgendermaßen aus:

var newGuid = function () {
    var result = '';
    var hexcodes = "0123456789abcdef".split("");

    for (var index = 0; index < 32; index++) {
        var value = Math.floor(Math.random() * 16);

        switch (index) {
        case 8:
            result += '-';
            break;
        case 12:
            value = 4;
            result += '-';
            break;
        case 16:
            value = value & 3 | 8;
            result += '-';
            break;
        case 20:
            result += '-';
            break;
        }
        result += hexcodes[value];
    }
    return result;
};

11

Dieser basiert auf dem Datum und fügt ein zufälliges Suffix hinzu, um die Eindeutigkeit sicherzustellen. Funktioniert gut für CSS-Kennungen. Es gibt immer so etwas zurück und ist leicht zu hacken:

uid-139410573297741

var getUniqueId = function (prefix) {
            var d = new Date().getTime();
            d += (parseInt(Math.random() * 100)).toString();
            if (undefined === prefix) {
                prefix = 'uid-';
            }
            d = prefix + d;
            return d;
        };

11

Einfacher Code, der crypto.getRandomValues(a)in unterstützten Browsern verwendet wird (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Vermeidet die Verwendung, Math.random()da dies zu Kollisionen führen kann (z. B. 20 Kollisionen für 4000 von Muxa in einer realen Situation erzeugte Benutzeroberflächen ).

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

Anmerkungen:

  • Optimiert für die Lesbarkeit des Codes und nicht für die Geschwindigkeit. Geeignet für einige hundert UUIDs pro Sekunde. Generiert ungefähr 10000 uuid () pro Sekunde in Chromium auf meinem Laptop unter Verwendung von http://jsbin.com/fuwigo/1 , um die Leistung zu messen.
  • Verwendet nur 8 für "y", da dies die Lesbarkeit des Codes vereinfacht (y darf 8, 9, A oder B sein).

11

Wenn Sie nur eine zufällige 128-Bit-Zeichenfolge in keinem bestimmten Format benötigen, können Sie Folgendes verwenden:

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

Welches wird so etwas zurückgeben 2350143528-4164020887-938913176-2513998651.


Übrigens, warum werden nur Zahlen und keine Zeichen generiert? viel weniger sicher
vsync

1
Sie können auch Zeichen (Buchstaben) wie Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
folgt

11

Nur eine weitere besser lesbare Variante mit nur zwei Mutationen.

function uuid4()
{
  function hex (s, b)
  {
    return s +
      (b >>> 4   ).toString (16) +  // high nibble
      (b & 0b1111).toString (16);   // low nibble
  }

  let r = crypto.getRandomValues (new Uint8Array (16));

  r[6] = r[6] >>> 4 | 0b01000000; // Set type 4: 0100
  r[8] = r[8] >>> 3 | 0b10000000; // Set variant: 100

  return r.slice ( 0,  4).reduce (hex, '' ) +
         r.slice ( 4,  6).reduce (hex, '-') +
         r.slice ( 6,  8).reduce (hex, '-') +
         r.slice ( 8, 10).reduce (hex, '-') +
         r.slice (10, 16).reduce (hex, '-');
}

Nun, die meisten js-Entwickler sind Webentwickler, und wir werden nicht verstehen, was bitweise Operatoren tun, da wir sie die meiste Zeit, die wir entwickeln, nicht verwenden. Eigentlich brauchte ich nie einen von ihnen, und ich bin seit 1997 ein js dev. Daher ist Ihr Beispielcode für den durchschnittlichen Webentwickler, der ihn liest, immer noch völlig unlesbar. Ganz zu schweigen davon, dass Sie immer noch Variablennamen mit einem Buchstaben verwenden, was es noch kryptischer macht. Lesen Sie wahrscheinlich Clean Code, vielleicht hilft das: amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
inf3rno

@ inf3rno verprügel ihn nicht, alle vorgeschlagenen Lösungen in diesem Thread sind kryptisch, aber sie sind korrekte Antworten, wenn man bedenkt, dass die Frage eine Art Einzeiler sein sollte. Das ist es, was Einzeiler kryptisch sind. Sie können es sich nicht leisten, für den durchschnittlichen Entwickler lesbar zu sein, aber sie speichern Bildschirmfläche, wo ein einfacher vorhergehender Kommentar ausreicht. Infolgedessen ist es auf diese Weise viel besser lesbar, als wenn es stattdessen in "lesbarem Code" gewesen wäre.
Tatsu

Zufällig! = Einzigartig
user1529413

@ user1529413 Ja. Die Eindeutigkeit erfordert einen Index.
14.

Dies ist meine Lieblingsantwort, da eine UUID als 16-Byte-Wert (128 Bit) erstellt wird und nicht als serialisierte, gut lesbare Form. Es wäre trivial einfach, das String-Zeug fallen zu lassen und einfach die richtigen Bits eines zufälligen 128-Bits zu setzen, was alles ist, was ein uuidv4 sein muss. Sie könnten es für kürzere URLs base64, es an eine Webassembly zurückgeben, es in weniger Speicherplatz als als Zeichenfolge speichern, es zu einem Puffer mit einer Größe von 4096 machen und 256 Benutzeroberflächen darin ablegen, in einer Browser-Datenbank speichern usw. Viel besser als von Anfang an alles als lange, hexadezimal codierte Zeichenfolge in Kleinbuchstaben zu haben.
Josh aus Qaribou vor

8

OK, mit dem UUID- Paket werden UUIDs der Versionen 1, 3, 4 und 5 unterstützt:

yarn add uuid

und dann:

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

Sie können dies auch mit vollständig festgelegten Optionen tun:

const v1options = {
  node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
  clockseq: 0x1234,
  msecs: new Date('2011-11-01').getTime(),
  nsecs: 5678
};
uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'

Weitere Informationen finden Sie auf der npm-Seite hier


6

Es ist wichtig, dass Sie gut getesteten Code verwenden, der von mehr als einem Mitwirkenden gepflegt wird, anstatt Ihre eigenen Sachen dafür zu peitschen. Dies ist einer der Orte, an denen Sie wahrscheinlich den stabilsten Code der kürzestmöglichen cleveren Version vorziehen möchten, die im X-Browser funktioniert, jedoch die Eigenheiten von Y nicht berücksichtigt, die häufig zu sehr schwer zu untersuchenden Fehlern führen, als sich nur zufällig manifestieren für einige Benutzer. Persönlich verwende ich uuid-js unter https://github.com/aurigadl/uuid-js, die bower aktiviert haben, damit ich problemlos Updates durchführen kann.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.