Die folgenden uuid
Umsetzung bietet eine verschiedene ES6 2020 Lösung mit BigInt
und konzentriert sich auf "Use case intent for a uuid
Entwurfsmuster"; insbesondere zur Verwendung mit indexedDb primaryKey
Szenarien, in denen eine einheitliche zeitliche Abfolge und Zusammenstellung wertvoll sind.
Angesichts der Tatsache, dass auf diesen Beitrag über 30 Antworten eingegangen sind, geht es also los...
Dieser Beitrag hat:
- ein "TL;DR"
code
Abschnitt mit/ohne Selbstbeteiligung es6 class Xuid
- a Anwendungsfall y Motivationen Diskussion Abschnitt bezüglich der es6
class Xuid
bereitgestellt Code .
TL;DR class Xuid
Lösung für generische v4 uuid
mit einer monotonen Uhr
Der folgende Code stammt aus der Smallscript-Datei EdgeS Web-Client-Bibliothek, die ich selbst geschrieben habe und die hier unter der freien MIT-Lizenz zur Verfügung gestellt wird. A GitHub-Version wird verfügbar sein, sobald das EdgeS Web-Client-Toolset freigegeben ist.
Beispiel für die Verwendung:
eval: console.log(Xuid.v4New)
emittiert: {1eb4a659-8bdc-4ce0-c002-b1d505d38ea8}
class Xuid {
//@ edges.sm.st, ess.dev: MIT license Smallscript/David Simmons 2020
//! Can't use `static const field = const` xbrowser (thus, const's duped)
static get v4New() {
const ns7Now = this.ns7Now, xnode48 = this.xnode48; let clock_seq13
// monotonic `clock_seq` guarantee (13-bits/time-quantum)
if(ns7Now <= this.ns7Now_prevSeq && this.ns7Now_prevSeq)
clock_seq13 = ((this.ns7Now_prevSeq += 1n) - ns7Now) & 0b1_1111_1111_1111n
else
clock_seq13 = 0n, this.ns7Now_prevSeq = ns7Now
const time60 = ((ns7Now << 4n) & 0xFFFF_FFFF_FFFF_0000n) |
(ns7Now & 0x0000_0000_0000_0FFFn),
v4 = 0x1_00000000_0000_0000_0000_000000000000n |
(time60 << 64n) | (0x00000000_0000_4000_0000_000000000000n) | // M: V4
(0b110n << 61n) | (clock_seq13 << 48n) | // N: Variant-2 time-seq collation
xnode48, s = v4.toString(16)//.substr(1)
return `{${s.substr(1,8)}-${s.substr(9,4)}-${s.substr(13,4)}-${
s.substr(17,4)}-${s.substr(21,12)}}`
}
static get xnode48()/*:<BigInt#48>*/{
if(this.xnode48_) return this.xnode48_
let clockSeqNode; if(typeof URL !== 'undefined' && URL.createObjectURL) {
const url = URL.createObjectURL(new Blob())
const id = (url.toString().split('/').reverse()[0]).split('-')
URL.revokeObjectURL(url)
clockSeqNode = BigInt('0x'+id[3]+id[4])
}
else {
const a4 = this.a4; this.getRandomValues(this.a4);
clockSeqNode = (BigInt(a4[2]) << 32n) | BigInt(a4[3])
}
// simulate the 48-bit node-id and 13-bit clock-seq
// to combine with 3-bit uuid-variant
return this.xnode48_ = clockSeqNode & 0xFFFF_FFFF_FFFFn;
}
static get jdNow()/*:<double#ns7>*/{
// return 2440587.5+Date.now()/864e5 // <- Date-quantum-ms form (7ns form below)
return this.jdFromNs7(this.ns7Now)
}
static get ns7Now()/*:<BigInt#60>*/{
if(typeof performance !== 'undefined' && performance.now)
Reflect.defineProperty(this, 'ns7Now',
Reflect.getOwnPropertyDescriptor(this,'ns7Now_performance'))
else
Reflect.defineProperty(this, 'ns7Now',
Reflect.getOwnPropertyDescriptor(this, 'ns7Now_Date'))
return this.ns7Now
}
static get ns7Now_Date()/*:<BigInt#60>*/{
// const epoch1582Ns7_bias = 0x1b2_1dd2_1381_4000 // V1 1582 Oct 15
// const epoch1601Ns7_bias = 0x19d_b1de_d53e_8000n // FILETIME base
const epoch1970Ns7 = BigInt(Date.now() * 1000_0.0)
return epoch1970Ns7 + 0x1b2_1dd2_1381_4000n
}
static get ns7Now_performance()/*:<BigInt#60>*/{
const epochPgNs7 = BigInt(performance.now()*/*15*/1000_0.0|/*17*/0)
if(!this.epoch1970PgNs7) // performance.timing.navigationStart
this.epoch1970PgNs7 = this.ns7Now_Date - epochPgNs7
return epochPgNs7 + this.epoch1970PgNs7
}
static dateFromJd(jd) {return new Date((jd - 2440587.5) * 864e5)}
static dateFromNs7(ns7) {
return new Date(Number(ns7 - 0x1b2_1dd2_1381_4000n) / 1000_0.0)}
static jdFromNs7(ns7) { // atomic-clock leap-seconds (ignored)
return 2440587.5 + (Number(ns7 - 0x1b2_1dd2_1381_4000n) / 864e9)
}
static ns7FromJd(jd) {
return BigInt((jd - 2440587.5) * 864e9) + 0x1b2_1dd2_1381_4000n
}
static getRandomValues(va/*:<Uint32Array>*/) {
if(typeof crypto !== 'undefined' && crypto.getRandomValues)
crypto.getRandomValues(va)
else for(let i = 0, n = va.length; i < n; i += 1)
va[i] = Math.random() * 0x1_0000_0000 >>> 0
}
static get a4() {return this.a4_ || (this.a4_ = new Uint32Array(4))}
static ntohl(v)/*:<BigInt>*/{
let r = '0x', sign = 1n, s = BigInt(v).toString(16)
if(s[0] == '-') s = s.substr(1), sign = -1n
for(let i = s.length; i > 0; i -= 2)
r += (i == 1) ? ('0' + s[i-1]) : s[i-2] + s[i-1]
return sign*BigInt(r)
}
static ntohl32(v)/*:<Number>*/{return Number(this.ntohl(v))}
}
Motivation
Während v4 uuid
definiert eine grundsätzlich zufällige uuid
ist es wünschenswert, eine uuid
Implementierung, die einige zusätzliche Merkmale unterstützen kann.
-
erstellt neue uuid
Werte schnell und effizient (mit BigInt
)
-
implementiert als eigenständiger Code mit einer nominal 80 loc
lesbar class
mit Kommentaren
-
enthält uuid
Einzigartigkeit durch monotone time
innerhalb einer context
-
stringifiziert, so dass die Zeichenkettenform:
- kollabiert basierend auf
time
und dann context
(mit uuid
Variante-2)
- in eine binäre Form zurückverwandelt, die die Daten korrekt identifiziert und wiederherstellt
time
-
enthält JavaScript
Taktgenauigkeit im Mikrosekundenbereich, sofern verfügbar
-
unterstützt umgebungsübergreifende Quanten von 100 Nanosekundeneinheiten auf der Grundlage des Julianischen Tages Epochenjahr 1582 Okt 15, V1-Kompatibilität. Auswahlmöglichkeiten, die ein einheitliches Zeit Zeitverhalten über ein Spektrum von Umgebungen und Anwendungsfällen hinweg im Einklang mit EdgeS
y ESS
Sprache Modell.
Besonders geeignet für die Verwendung von Datenbanken mit Einrichtungen wie SQLite.
-
verwendet es6 class
Design zur Vereinfachung der Erweiterbarkeit für nominelle Arbeiten zu erweitern um andere Funktionen zu ermöglichen uuid
Varianten
-
für diese Buchung vereinheitlichte und integrierte grundlegende time
y zugehörige eswc Bibliotheks-APIs.
- Julianischer Tag API
- ns7 (100-Nano-Sekunden-Quantum) API
ntohl
API für die bequeme Neuordnung von Endian BigInt
String-Darstellungen
-
abgeleitet von QKS Smalltalk 1991, AOS® [Agile Object System; Agents Object System] Technologie der Engine-Familie für Sprache, Framework und Laufzeiten bewahrt sie Kompatibilität mit einer Vielzahl aktueller und historischer Host-Betriebssysteme Modelle.
-
und zwar dort, wo die Xuid
scalar string format mit geschweiften Klammern unterstützt guid
, uuid
y uid
( git
, fossil
, SqLite
repo-id) Vertretungen, FILETIME
など。
wie in: {1eb4a659-8bdc-4ce0-c002-b1d505d38ea8}
-
und nicht zuletzt bietet es eine wünschenswerte Lösung für die Arbeit mit indexedDb object stores
wobei die Verwendung eines uuid
als die primaryKey
begehrenswert wird.
- Aktivierung von Auto-Sequencing-Funktionen
- natürliche Sortierung der Zeichenketten
- beachten Sie die subtil Verwendung von
uuid
Variante-2 umkehren time
Wert des LHS in seinem stringiert Form.
- natürlich und einfach
put
Aktualisierung von
- natürliches Muster für
efs
(EdgeS virtuelles Dateisystem - automatische Namen)
service-worker
y cloud-server
Aktionen synchronisieren und replizieren
Zusammenfassung
Obwohl Kurz und bündig Ich hoffe, dass dies für den Moment eine ausreichende Erklärung ist; versuchen Sie es .
Und, bitte Sie können gerne Kommentare, Feedback oder Vorschläge einreichen.
Bei der Veröffentlichung als Teil des EdgeS Web-Client eswc
Bibliothek auf GitHub die indexedDb Nutzungsmuster mit efs
werden als Beispiele für ihre Design-Absichten, die Effizienz und Benutzerfreundlichkeit mit indexedDb y zugehörige PWA sync
y replicate
Szenarien.
Verwandte Seiten
Benchmarking uuid
s/sec
const start = Xuid.ns7Now
for(let i = 100000; i; i -=1)
Xuid.v4New
const end = Xuid.ns7Now
console.log(`Delta 7ns: ${(end-start)/100000n}`)
Daraus resultiert: Werte von 16..20 => ~2 Mikro-Sekunden => 500,000 uuid
s/sec
38 Stimmen
GUIDs, die als Zeichenketten dargestellt werden, sind mindestens 36 und höchstens 38 Zeichen lang und entsprechen dem Muster ^\{?[a-zA-Z0-9]{36}?\}$ und sind daher immer in ASCII.
5 Stimmen
David Bau bietet einen viel besseren Zufallszahlengenerator an, der unter davidbau.com/archives/2010/01/30/ Ich habe einen etwas anderen Ansatz zur Erzeugung von UUIDs unter blogs.cozi.com/tech/2010/04/generating-uuids-in-javascript.html
1 Stimmen
Seltsam, dass das noch niemand erwähnt hat, aber der Vollständigkeit halber: Es gibt eine Fülle von guid-Generatoren auf npm Ich wette, die meisten von ihnen funktionieren auch im Browser.
1 Stimmen
Wenn jemand mehr Optionen wie verschiedene Versionen der uuid und Unterstützung für nicht standardmäßige guids wünscht, können REST-basierte uuid-Generierungsdienste wie diese [ fungenerators.com/api/uuid ] sind ebenfalls eine attraktive Option.
2 Stimmen
Etwa 12 Jahre später mit
BigInt
und ES6-Klassen können auch andere Techniken eingesetzt werden, die Raten von 500.000 uuid/sec ermöglichen. Siehe Referenz5 Stimmen
Comme andere haben erwähnt Wenn Sie nur eine kleine Anzahl von UUIDs in einem Browser erzeugen, verwenden Sie einfach
URL.createObjectURL(new Blob()).substr(-36)
. ( Ausgezeichnete Browser-Unterstützung ). (Um Speicherlecks zu vermeiden, URL.revokeObjectURL(url) aufrufen )1 Stimmen
Wenn Sie ein unternehmenskritisches Problem haben, schreiben Sie besser einen Endpunkt, der mit Pyhton geschrieben wurde, und rufen ihn auf. Weil es so implementiert ist, wie unter datatracker.ietf.org/doc/html/rfc4122.html