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.
javascript
guid
uuid
Jason Cohen
quelle
quelle
Antworten:
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:
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.Math.random
)Entwickler, die Code für Produktionsumgebungen schreiben, werden daher aufgefordert, eine strenge, gut gewartete Implementierung wie das UUID- Modul zu verwenden.
quelle
Für eine RFC4122- Version 4-kompatible Lösung ist diese Einzeiler -Lösung die kompakteste, die ich mir vorstellen kann :
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, jedochMath.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
crypto
API und ein wenig JS-Assistenten verwendet, für die ich keine Anerkennung finden kann :Update, 06.01.2020 : In Arbeit ist ein Vorschlag für ein Standardmodul
uuid
als Teil der JS-Sprachequelle
c== 'x'
stattc === 'x'
. Weil jshint fehlgeschlagen ist.Ich mag es wirklich, wie sauber Broofas Antwort ist, aber es ist bedauerlich, dass schlechte Implementierungen
Math.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.random
mü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:Hier ist eine Geige zum Testen.
quelle
new Date().getTime()
nicht jede Millisekunde aktualisiert wird. Ich bin nicht sicher, wie sich dies auf die erwartete Zufälligkeit Ihres Algorithmus auswirkt.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 .d = Math.floor(d/16);
?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, FunktionsaufrufetoString()
undMath.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 wegzuwerfengenerateQuickGUID
.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-konformengenerateQuickGuid
: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:
Es wird also
x
durch eine zufällige hexadezimale Ziffery
mit zufälligen Daten ersetzt (außer dass die obersten 2 Bits10
gemäß der RFC-Spezifikation erzwungen werden), und der reguläre Ausdruck stimmt nicht mit den Zeichen-
oder überein4
, 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,4
während Broofa dies nicht tat. Beachten Sie auch, dass wir die String-Array-Indizierung verwenden können, um seine raffinierte String-Vorlagenarchitektur beizubehalten:Grundsätzlich führt dieselbe innere Logik, außer dass wir nach
-
oder suchen4
und eine while-Schleife (anstelle vonreplace()
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:
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:
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 ().
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:
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.
quelle
Math.random()*0xFFFFFFFF
Zeilen solltenMath.random()*0x100000000
vollständig zufällig sein und>>>0
stattdessen 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.getRandomValues
falls 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.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).
quelle
var s = new Array(36);
Code-Snippet anzeigen
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:
Code-Snippet anzeigen
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
quelle
[slug, date, random].join("_")
zum Erstellenusr_1dcn27itd_hj6onj6phr
. Dadurch wird die ID auch als "Erstellt am" -Feld verwendetSchnellste 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:
Um die Leistung zu testen, können Sie diesen Code ausführen:
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:
Math.random()
Funktion gibt eine Dezimalzahl zwischen 0 und 1 mit 16 Stellen nach dem Dezimalbruchpunkt zurück (zum Beispiel0.4363923368509859
).0.6fb7687f
).Math.random().toString(16)
.0.
Präfix (0.6fb7687f
=>6fb7687f
) ab und erhalten eine Zeichenfolge mit acht hexadezimalen Zeichen.(Math.random().toString(16).substr(2,8)
.Math.random()
Funktion0.4363
aufgrund von Nullen am Ende eine kürzere Zahl zurück (zum Beispiel ) (aus dem obigen Beispiel ist die Zahl tatsächlich0.4363000000000000
). Deshalb füge ich diese Zeichenfolge hinzu"000000000"
(eine Zeichenfolge mit neun Nullen) und schneide sie dann mit dersubstr()
Funktion ab, um sie genau auf neun Zeichen zu setzen (wobei Nullen rechts ausgefüllt werden).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:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
.XXXXXXXX
und-XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
Ders
Parameter teilt der Funktion mit, ob Bindestriche hinzugefügt werden sollen oder nicht._p8() + _p8(true) + _p8(true) + _p8()
und geben sie zurück.Link zu diesem Beitrag in meinem Blog
Genießen! :-)
quelle
Hier ist eine Kombination der am häufigsten bewerteten Antwort mit einer Problemumgehung für die Kollisionen von Chrome :
Auf jsbin, wenn Sie es testen möchten.
quelle
, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxxx", die sie liefertxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
.Hier ist eine völlig nicht konforme, aber sehr leistungsfähige Implementierung zum Generieren einer ASCII-sicheren GUID-ähnlichen eindeutigen Kennung.
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.
Hier ist der Timing-Code.
quelle
Hier ist eine Lösung vom 9. Oktober 2011 aus einem Kommentar des Benutzers jed unter https://gist.github.com/982883 :
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:
quelle
Aus dem technischen Blog von sagi shkedy :
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.
quelle
Sie können node-uuid verwenden ( https://github.com/kelektiv/node-uuid )
Einfache und schnelle Generierung von RFC4122- UUIDS.
Eigenschaften:
Installation mit NPM:
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:
ES6:
quelle
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.
quelle
Einfaches JavaScript-Modul als Kombination der besten Antworten in diesem Thread.
Verwendungszweck:
quelle
GUID
alsstring
. Ihre Antwort befasst sich zumindest mit der viel effizienteren Speicherung mit aUint16Array
. DietoString
Funktion sollte die binäre Darstellung in einem JavaScript verwendenobject
Diese UUID der Version 4 (erstellt aus Pseudozufallszahlen):
Hier ist ein Beispiel der generierten UUIDs:
quelle
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.
quelle
JavaScript-Projekt auf GitHub - https://github.com/LiosK/UUID.js
quelle
quelle
Ich wollte die Antwort von broofa verstehen, also habe ich sie erweitert und Kommentare hinzugefügt:
quelle
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.
quelle
Für diejenigen, die eine rfc4122 Version 4-kompatible Lösung mit Geschwindigkeitsüberlegungen wünschen (wenige Aufrufe von Math.random ()):
Die obige Funktion sollte ein angemessenes Gleichgewicht zwischen Geschwindigkeit und Zufälligkeit aufweisen.
quelle
ES6-Probe
quelle
Der bessere Weg:
Minimiert:
quelle
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:quelle
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
quelle
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 ).Anmerkungen:
quelle
Wenn Sie nur eine zufällige 128-Bit-Zeichenfolge in keinem bestimmten Format benötigen, können Sie Folgendes verwenden:
Welches wird so etwas zurückgeben
2350143528-4164020887-938913176-2513998651
.quelle
Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
Nur eine weitere besser lesbare Variante mit nur zwei Mutationen.
quelle
OK, mit dem UUID- Paket werden UUIDs der Versionen 1, 3, 4 und 5 unterstützt:
und dann:
Sie können dies auch mit vollständig festgelegten Optionen tun:
Weitere Informationen finden Sie auf der npm-Seite hier
quelle
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.
quelle