J'essaie de créer des identificateurs uniques au monde en JavaScript. Je ne sais pas quelles routines sont disponibles sur tous les navigateurs, à quel point le générateur de nombres aléatoires est "aléatoire" et prédéfini, etc.
Le GUID / UUID doit être d'au moins 32 caractères et doit rester dans la plage ASCII pour éviter les problèmes lors de leur passage.
javascript
guid
uuid
Jason Cohen
la source
la source
Réponses:
UUID (Universally Unique IDentifier), également connu sous le nom de GUID (Globally Unique IDentifier), selon la RFC 4122 , sont des identifiants conçus pour fournir certaines garanties d'unicité.
Bien qu'il soit possible d'implémenter des UUID conformes à la RFC dans quelques lignes de JS (par exemple, voir la réponse de @ broofa , ci-dessous), il existe plusieurs pièges courants:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
", où x est l'un de [0-9, af] M est l'un de [1-5] et N est [8, 9, a ou b]]Math.random
)Ainsi, les développeurs écrivant du code pour les environnements de production sont encouragés à utiliser une implémentation rigoureuse et bien entretenue telle que le module uuid .
la source
Pour une solution compatible RFC4122 version 4, cette solution à une ligne (ish) est la plus compacte que j'ai pu trouver:
Mise à jour, 2015-06-02 : sachez que l'unicité des UUID dépend fortement du générateur de nombres aléatoires (RNG) sous-jacent. La solution ci-dessus utilise
Math.random()
pour la brièveté, cependant,Math.random()
n'est pas garanti d'être un RNG de haute qualité. Voir l' excellent ouvrage d' Adam Hyland sur Math.random () pour plus de détails. Pour une solution plus robuste, envisagez d'utiliser le module uuid , qui utilise des API RNG de meilleure qualité.Mise à jour, 2015-08-26 : En guise de note latérale, cet élément essentiel décrit comment déterminer le nombre d'ID pouvant être générés avant d'atteindre une certaine probabilité de collision. Par exemple, avec les UUID RFC4122 3.26x10 15 version 4, vous avez une chance sur un million de collision.
Mise à jour, 28/06/2017 : Un bon article de développeurs Chrome discutant de l'état de la qualité PRNG Math.random dans Chrome, Firefox et Safari. tl; dr - À la fin de 2015, c'est "assez bien", mais pas la qualité cryptographique. Pour résoudre ce problème, voici une version mise à jour de la solution ci-dessus qui utilise ES6, l'
crypto
API et un peu de magie JS pour laquelle je ne peux pas m'attribuer le mérite :Mise à jour, 2020-01-06 : Une proposition de norme est en préparation
uuid
module dans le langage JSla source
c== 'x'
au lieu dec === 'x'
. Parce que jshint a échoué.J'aime vraiment la pureté de la réponse de Broofa , mais il est regrettable que les mauvaises implémentations de
Math.random
laissent la chance de collision.Voici une solution conforme à la RFC4122 version 4 similaire qui résout ce problème en compensant les 13 premiers nombres hexadécimaux par une partie hexadécimale de l'horodatage, et une fois épuisée compensée par une partie hexadécimale des microsecondes depuis le chargement de page. De cette façon, même s'il
Math.random
est sur la même graine, les deux clients devraient générer l'UUID exactement le même nombre de microsecondes depuis le chargement de page (si le temps de haute performance est pris en charge) ET à exactement la même milliseconde (ou plus de 10 000 ans plus tard) pour obtenir le même UUID:Voici un violon à tester.
la source
new Date().getTime()
n'est pas mis à jour toutes les millisecondes. Je ne sais pas comment cela affecte le caractère aléatoire attendu de votre algorithme.performance.now()
ne sont pas limités à une résolution d'une milliseconde. Au lieu de cela, ils représentent les temps sous forme de nombres à virgule flottante avec une précision allant jusqu'à la microseconde . Contrairement à Date.now, les valeurs renvoyées par performance.now () augmentent toujours à un taux constant , indépendamment de l'horloge système qui peut être ajustée manuellement ou biaisée par un logiciel tel que le Network Time Protocol.d = Math.floor(d/16);
?La réponse de broofa est assez lisse, en effet - incroyablement intelligent, vraiment ... conforme rfc4122, quelque peu lisible et compact. Impressionnant!
Mais si vous regardez cette expression régulière, ces nombreux
replace()
rappelstoString()
etMath.random()
appels de fonction (où il n'utilise que 4 bits du résultat et gaspille le reste), vous pouvez commencer à vous interroger sur les performances. En effet, joelpt a même décidé de lancer RFC pour la vitesse GUID générique avecgenerateQuickGUID
.Mais, pouvons-nous obtenir la vitesse et la conformité RFC? Je dis oui! Pouvons-nous maintenir la lisibilité? Eh bien ... Pas vraiment, mais c'est facile si vous suivez.
Mais d'abord, mes résultats, par rapport à broofa,
guid
(la réponse acceptée) et le non-rfc conformegenerateQuickGuid
:Donc, à ma 6e itération d'optimisations, j'ai battu la réponse la plus populaire de plus de 12X , la réponse acceptée de plus de 9X et la réponse rapide non conforme de 2-3X . Et je suis toujours conforme rfc4122.
Intéressé par comment? J'ai mis la source complète sur http://jsfiddle.net/jcward/7hyaC/3/ et sur http://jsperf.com/uuid-generator-opt/4
Pour une explication, commençons par le code de broofa:
Il remplace donc
x
par n'importe quel chiffre hexadécimal aléatoire,y
avec des données aléatoires (sauf forcer les 2 premiers bits10
selon la spécification RFC), et l'expression régulière ne correspond pas à la-
ou4
caractères , il n'a donc pas à les traiter. Très, très lisse.La première chose à savoir est que les appels de fonction sont chers, tout comme les expressions régulières (bien qu'il n'utilise que 1, il a 32 rappels, un pour chaque correspondance, et dans chacun des 32 rappels, il appelle Math.random () et v. toString (16)).
La première étape vers les performances consiste à éliminer le RegEx et ses fonctions de rappel et à utiliser une boucle simple à la place. Cela signifie que nous devons gérer les caractères
-
et4
, contrairement à broofa. Notez également que nous pouvons utiliser l'indexation de tableau de chaînes pour conserver son architecture de modèle de chaîne lisse:Fondamentalement, la même logique intérieure, sauf que nous vérifions
-
ou4
, et en utilisant une boucle while (au lieu dereplace()
rappels) nous apporte une amélioration de presque 3 fois!La prochaine étape est une petite sur le bureau mais fait une différence décente sur mobile. Faisons moins d'appels Math.random () et utilisons tous ces bits aléatoires au lieu de jeter 87% d'entre eux avec un tampon aléatoire qui est décalé à chaque itération. Déplaçons également cette définition de modèle hors de la boucle, juste au cas où cela aiderait:
Cela nous permet d'économiser 10-30% selon la plate-forme. Pas mal. Mais la prochaine grande étape se débarrasse des appels de la fonction toString avec un classique d'optimisation - la table de recherche. Une simple table de recherche à 16 éléments effectuera le travail de toString (16) en beaucoup moins de temps:
La prochaine optimisation est un autre classique. Étant donné que nous ne gérons que 4 bits de sortie à chaque itération de boucle, réduisons le nombre de boucles de moitié et traitons 8 bits à chaque itération. C'est délicat car nous devons encore gérer les positions de bits conformes à la RFC, mais ce n'est pas trop difficile. Nous devons ensuite créer une table de recherche plus grande (16x16 ou 256) pour stocker 0x00 - 0xff, et nous la construisons une seule fois, en dehors de la fonction e5 ().
J'ai essayé un e6 () qui traite 16 bits à la fois, en utilisant toujours la LUT à 256 éléments, et cela a montré les rendements décroissants de l'optimisation. Bien qu'il ait eu moins d'itérations, la logique interne a été compliquée par l'augmentation du traitement, et il a effectué la même chose sur le bureau, et seulement 10% plus rapide sur le mobile.
La dernière technique d'optimisation à appliquer - déroule la boucle. Puisque nous bouclons un nombre fixe de fois, nous pouvons techniquement tout écrire à la main. J'ai essayé cela une fois avec une seule variable aléatoire r que je continuais de réassigner, et les performances étaient optimisées. Mais avec quatre variables assignées à l'avance des données aléatoires, puis en utilisant la table de recherche et en appliquant les bits RFC appropriés, cette version les fume toutes:
Modualisé: http://jcward.com/UUID.js -
UUID.generate()
Le plus drôle, c'est que générer 16 octets de données aléatoires est la partie la plus facile. L'astuce consiste à l'exprimer au format String avec la conformité RFC, et c'est le plus étroitement accompli avec 16 octets de données aléatoires, une boucle déroulée et une table de recherche.
J'espère que ma logique est correcte - il est très facile de se tromper dans ce genre de travail fastidieux. Mais les sorties me semblent bonnes. J'espère que vous avez apprécié cette course folle grâce à l'optimisation du code!
Soyez avisé: mon objectif principal était de montrer et d'enseigner des stratégies d'optimisation potentielles. D'autres réponses couvrent des sujets importants tels que les collisions et les nombres vraiment aléatoires, qui sont importants pour générer de bons UUID.
la source
Math.random()*0xFFFFFFFF
lignes doivent êtreMath.random()*0x100000000
pour un caractère aléatoire complet, et>>>0
doivent être utilisées au lieu de|0
garder les valeurs non signées (bien qu'avec le code actuel, je pense que ça va bien même si elles sont signées). Enfin, ce serait une très bonne idée d'utiliser ces jours-ciwindow.crypto.getRandomValues
si disponible, et de ne recourir à Math.random qu'en cas de nécessité absolue. Math.random pourrait bien avoir moins de 128 bits d'entropie, auquel cas cela serait plus vulnérable aux collisions que nécessaire.Voici un code basé sur RFC 4122 , section 4.4 (Algorithmes pour créer un UUID à partir d'un nombre vraiment aléatoire ou pseudo-aléatoire).
la source
var s = new Array(36);
Afficher l'extrait de code
Si les ID sont générés à plus d'une milliseconde d'intervalle, ils sont 100% uniques.
Si deux ID sont générés à des intervalles plus courts, et en supposant que la méthode aléatoire est vraiment aléatoire, cela générerait des ID qui sont 99,9999999999999999% susceptibles d'être uniques au monde (collision dans 1 sur 10 ^ 15)
Vous pouvez augmenter ce nombre en ajoutant plus de chiffres, mais pour générer des identifiants 100% uniques, vous devrez utiliser un compteur global.
si vous avez besoin de la compatibilité RFC, cette mise en forme passera comme un GUID valide de la version 4:
Afficher l'extrait de code
Modifier: Le code ci-dessus suit l'intention, mais pas la lettre du RFC. Entre autres écarts, il y a quelques chiffres aléatoires courts. (Ajoutez plus de chiffres aléatoires si vous en avez besoin) L'avantage est que c'est très rapide :) Vous pouvez tester la validité de votre GUID ici
la source
[slug, date, random].join("_")
pour créerusr_1dcn27itd_hj6onj6phr
. Cela fait en sorte que l'ID se double également d'un champ "créé à"GUID le plus rapide comme méthode de générateur de chaînes dans le format
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
. Cela ne génère pas de GUID conforme aux normes.Dix millions d'exécutions de cette implémentation ne prennent que 32,5 secondes, ce qui est la plus rapide que j'ai jamais vue dans un navigateur (la seule solution sans boucles / itérations).
La fonction est aussi simple que:
Pour tester les performances, vous pouvez exécuter ce code:
Je suis sûr que la plupart d'entre vous comprendront ce que j'ai fait là-bas, mais il y a peut-être au moins une personne qui aura besoin d'une explication:
L'algorithme:
Math.random()
fonction renvoie un nombre décimal compris entre 0 et 1 avec 16 chiffres après le point de fraction décimale (par exemple0.4363923368509859
).0.6fb7687f
).Math.random().toString(16)
.0.
préfixe (0.6fb7687f
=>6fb7687f
) et obtenons une chaîne de huit caractères hexadécimaux.(Math.random().toString(16).substr(2,8)
.Math.random()
fonction retourne un nombre plus court (par exemple0.4363
), en raison de zéros à la fin (dans l'exemple ci-dessus, en fait, le nombre est0.4363000000000000
). C'est pourquoi j'ajoute à cette chaîne"000000000"
(une chaîne avec neuf zéros) puis je la coupe avecsubstr()
fonction pour lui donner exactement neuf caractères (en remplissant les zéros à droite).Math.random()
fonction retournera exactement 0 ou 1 (probabilité de 1/10 ^ 16 pour chacun d'eux). C'est pourquoi nous avons dû lui ajouter neuf zéros ("0"+"000000000"
ou"1"+"000000000"
), puis le couper du deuxième index (3e caractère) avec une longueur de huit caractères. Pour le reste des cas, l'ajout de zéros ne nuira pas au résultat car il le coupe de toute façon.Math.random().toString(16)+"000000000").substr(2,8)
.L'Assemblée:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
.XXXXXXXX
et-XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
, les
paramètre indique à la fonction s'il faut ajouter des tirets ou non._p8() + _p8(true) + _p8(true) + _p8()
et le renvoyons.Lien vers cet article sur mon blog
Prendre plaisir! :-)
la source
Voici une combinaison de la réponse la plus votée , avec une solution de contournement pour les collisions de Chrome :
Sur jsbin si vous voulez le tester.
la source
, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`, elle donnexxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
.Voici une implémentation totalement non conforme mais très performante pour générer un identifiant unique de type GUID sécurisé ASCII.
Génère 26 [a-z0-9] caractères, produisant un UID qui est à la fois plus court et plus unique que les GUID conformes RFC. Des tirets peuvent être insignifiants si la lisibilité est importante.
Voici des exemples d'utilisation et des délais pour cette fonction et plusieurs autres réponses à cette question. Le chronométrage a été effectué sous Chrome m25, 10 millions d'itérations chacun.
Voici le code temporel.
la source
Voici une solution datée du 9 octobre 2011 à partir d'un commentaire de l'utilisateur jed sur https://gist.github.com/982883 :
Cela atteint le même objectif que la réponse actuellement la mieux notée , mais dans 50+ octets de moins en exploitant la coercition, la récursivité et la notation exponentielle. Pour les curieux de savoir comment cela fonctionne, voici la forme annotée d'une ancienne version de la fonction:
la source
Du blog technique de sagi shkedy :
Il existe d'autres méthodes qui impliquent l'utilisation d'un contrôle ActiveX, mais restez à l'écart de celles-ci!
Edit: J'ai pensé qu'il valait la peine de souligner qu'aucun générateur GUID ne peut garantir des clés uniques (consultez l' article wikipedia ). Il y a toujours un risque de collision. Un GUID offre simplement un univers de touches suffisamment grand pour réduire le changement de collisions à presque nul.
la source
Vous pouvez utiliser node-uuid ( https://github.com/kelektiv/node-uuid )
Génération simple et rapide d' UUIDS RFC4122.
Fonctionnalités:
Installer à l'aide de NPM:
Ou en utilisant uuid via un navigateur:
Télécharger le fichier brut (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Télécharger le fichier brut (uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid / master / v4.js
Vous voulez encore plus petit? Vérifiez ceci: https://gist.github.com/jed/982883
Usage:
ES6:
la source
ÉDITER:
Revisité mon projet qui utilisait cette fonction et n'aimait pas la verbosité. - Mais il fallait un caractère aléatoire approprié.
Une version basée sur la réponse de Briguy37 et certains opérateurs au niveau du bit pour extraire les fenêtres de taille quartet du tampon.
Devrait adhérer au schéma RFC Type 4 (aléatoire), car j'ai eu des problèmes lors de la dernière analyse des uuids non conformes avec l'UUID de Java.
la source
Module JavaScript simple comme combinaison des meilleures réponses dans ce fil.
Usage:
la source
GUID
tant questring
. Votre réponse aborde au moins le stockage beaucoup plus efficace en utilisant aUint16Array
. LatoString
fonction devrait utiliser la représentation binaire dans un JavaScriptobject
Cela crée la version 4 UUID (créée à partir de nombres pseudo aléatoires):
Voici un échantillon des UUID générés:
la source
Eh bien, cela a déjà un tas de réponses, mais malheureusement, il n'y a pas de "vrai" hasard dans le tas. La version ci-dessous est une adaptation de la réponse de broofa, mais mise à jour pour inclure une "vraie" fonction aléatoire qui utilise des bibliothèques de cryptographie lorsqu'elles sont disponibles, et la fonction Alea () comme solution de rechange.
la source
Projet JavaScript sur GitHub - https://github.com/LiosK/UUID.js
la source
la source
Je voulais comprendre la réponse de broofa, alors je l'ai développée et ajouté des commentaires:
la source
Ajustement de mon propre générateur UUID / GUID avec quelques extras ici .
J'utilise le générateur de nombres aléatoires Kybos suivant pour être un peu plus cryptographique.
Ci-dessous mon script avec les méthodes Mash et Kybos de baagoe.com exclues.
la source
Pour ceux qui souhaitent une solution compatible rfc4122 version 4 avec des considérations de vitesse (quelques appels à Math.random ()):
La fonction ci-dessus devrait avoir un équilibre décent entre la vitesse et le hasard.
la source
Échantillon ES6
la source
La meilleure façon:
Minimisé:
la source
Je sais, c'est une vieille question. Juste pour être complet, si votre environnement est SharePoint, il existe une fonction utilitaire appelée
SP.Guid.newGuid
( lien msdn ) qui crée un nouveau guid. Cette fonction se trouve dans le fichier sp.init.js. Si vous réécrivez cette fonction (pour supprimer d'autres dépendances d'autres fonctions privées), cela ressemble à ceci:la source
Celui-ci est basé sur la date et ajoute un suffixe aléatoire pour "garantir" l'unicité. Fonctionne bien pour les identificateurs CSS. Il renvoie toujours quelque chose comme et est facile à pirater:
uid-139410573297741
la source
Code simple qui utilise
crypto.getRandomValues(a)
sur les navigateurs pris en charge (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Évite d'utiliserMath.random()
car cela peut provoquer des collisions (par exemple 20 collisions pour 4000 uuids générés en situation réelle par Muxa ).Remarques:
la source
Si vous avez juste besoin d'une chaîne aléatoire de 128 bits sans format particulier, vous pouvez utiliser:
Qui retournera quelque chose comme
2350143528-4164020887-938913176-2513998651
.la source
Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
Juste une autre variante plus lisible avec seulement deux mutations.
la source
OK, en utilisant le package uuid , il prend en charge les UUID des versions 1, 3, 4 et 5 :
et alors:
Vous pouvez également le faire avec des options entièrement spécifiées:
Pour plus d'informations, visitez la page npm ici
la source
Il est important d'utiliser du code bien testé qui est maintenu par plus de 1 contributeurs au lieu de fouetter vos propres trucs pour cela. C'est l'un des endroits où vous souhaitez probablement préférer le code le plus stable à la version intelligente la plus courte possible qui fonctionne dans le navigateur X, mais ne tient pas compte des particularités de Y, ce qui entraînerait souvent des enquêtes très difficiles sur les bogues plutôt que de se manifester de manière aléatoire. pour certains utilisateurs. Personnellement, j'utilise uuid-js sur https://github.com/aurigadl/uuid-js qui est activé pour que je puisse prendre des mises à jour facilement.
la source