react Créer un GUID/UUID en JavaScript?




uuid v4 (24)

J'essaie de créer des identificateurs uniques en JavaScript en JavaScript. Je ne sais pas quelles routines sont disponibles sur tous les navigateurs, dans quelle mesure le générateur de nombres aléatoires intégré est "aléatoire", etc.

Le GUID / UUID doit comporter au moins 32 caractères et doit rester dans la plage ASCII pour éviter les problèmes lors de leur transmission.


Bizarre que personne n’en ait encore parlé, mais pour des raisons d’intégralité, il existe une pléthore de générateurs de guid sur npm. Je suis prêt à parier que la plupart d’entre eux fonctionnent également dans un navigateur.


Vous pouvez utiliser node-uuid ( https://github.com/kelektiv/node-uuid )

Génération simple et rapide de la ietf.org/rfc/rfc4122.txt UUIDS.

Caractéristiques:

  • Générer des UUID RFC4122 version 1 ou version 4
  • S'exécute dans node.js et les navigateurs.
  • Génération aléatoire # cryptographique forte sur les plates-formes de support.
  • Faible encombrement (Vous voulez quelque chose de plus petit? https://gist.github.com/982883 )

Installer à l'aide de NPM:

npm install uuid

Ou en utilisant uuid via le 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? Découvrez ceci: https://gist.github.com/jed/982883

Usage:

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

Projet JavaScript sur GitHub - https://github.com/LiosK/UUID.js

UUID.js Le générateur UUID conforme à RFC pour JavaScript.

Voir RFC 4122 ietf.org/rfc/rfc4122.txt .

Features Génère des UUID conformes à la norme RFC 4122.

Les UUID de la version 4 (UUID de nombres aléatoires) et les UUID de la version 1 (UUID temporels) sont disponibles.

L'objet UUID permet une variété d'accès à l'UUID, y compris l'accès aux champs de l'UUID.

La résolution d'horodatage faible de JavaScript est compensée par des nombres aléatoires.


Du bon vieux Wikipédia, il existe un lien vers une implémentation UUID en javascript.

Il semble assez élégant et pourrait peut-être être amélioré en salant avec un hachage de l'adresse IP du client. Ce hachage pourrait peut-être être inséré dans le document HTML côté serveur pour être utilisé par le javascript côté client.

MISE À JOUR: Le site d'origine a été modifié, voici la version mise à jour


Il y a eu quelques tentatives en ce sens. La question est la suivante: voulez-vous des GUID réels ou juste des nombres aléatoires ressemblant à des GUID? Il est assez facile de générer des nombres aléatoires.

function guid() {
  function s4() {
    return Math.floor((1 + Math.random()) * 0x10000)
      .toString(16)
      .substring(1);
  }
  return s4() + s4() + '-' + s4() + '-' + s4() + '-' + s4() + '-' + s4() + s4() + s4();
}

Cependant, notez que ces valeurs ne sont pas des GUID authentiques .

Remarque : l'extrait de code fourni ne suit pas la RFC4122, ce qui nécessite que la version ( 4 ) soit intégrée à la chaîne de sortie générée. N'utilisez pas cette réponse si vous avez besoin d'un GUID conforme.

Utilisation:

var uuid = guid();

Démo:

function guid() {
  return "ss-s-s-s-sss".replace(/s/g, s4);
}

function s4() {
  return Math.floor((1 + Math.random()) * 0x10000)
    .toString(16)
    .substring(1);
}

document.getElementById('jsGenId').addEventListener('click', function() {
  document.getElementById('jsIdResult').value = guid();
})
input { font-family: monospace; }
<button id="jsGenId" type="button">Generate GUID</button>
<br>
<input id="jsIdResult" type="text" placeholder="Results will be placed here..." readonly size="40"/>


Voici une combinaison de la réponse la plus votée , avec une solution de contournement pour les collisions de Chrome :

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

    :

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

Sur jsbin si vous voulez le tester.


Voici une implémentation totalement non conforme mais très performante permettant de générer un identifiant unique de type GUID conforme à la norme ASCII.

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

Génère 26 caractères [a-z0-9], générant un UID à la fois plus court et plus unique que les GUID conformes à RFC. Des tirets peuvent être ajoutés de manière triviale si la lisibilité est importante.

Voici des exemples d’utilisation et des horaires pour cette fonction, ainsi que plusieurs autres réponses de cette question. Le chronométrage a été effectué sous Chrome m25, 10 millions d’itérations chacun.

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

Voici le code de chronométrage.

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

var uniqueId = Math.random().toString(36).substring(2) 
               + (new Date()).getTime().toString(36);

Si les ID sont générés à plus d'une milliseconde de distance, ils sont uniques à 100%.

Si deux ID sont générés à des intervalles plus rapprochés et en supposant que la méthode aléatoire soit réellement aléatoire, cela générera des ID à 99,99999999999999% susceptibles d'être globalement uniques (collision dans 1 sur 10 ^ 15).

Vous pouvez augmenter ce nombre en ajoutant plus de chiffres, mais pour générer 100% d'identifiants uniques, vous devez utiliser un compteur global.

document.getElementById("unique").innerHTML =
  Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
<div id="unique">
</div>


Sur le blog technique de 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;
}

Il existe d'autres méthodes qui impliquent l'utilisation d'un contrôle ActiveX, mais restez à l'écart de celles-ci!

EDIT: Je pensais que cela valait la peine de souligner qu'aucun générateur de GUID ne peut garantir des clés uniques (consultez l' article de Wikipédia ). Il y a toujours une chance de collision. Un GUID offre simplement un assez grand nombre de clés pour réduire à néant le changement de collision.


J'aime vraiment à quel point la réponse de Broofa est propre, mais il est regrettable que de mauvaises applications de Math.random laissent une chance à la collision.

Voici une ietf.org/rfc/rfc4122.txt similaire ietf.org/rfc/rfc4122.txt version 4 de ietf.org/rfc/rfc4122.txt qui résout ce problème en décalant les 13 premiers nombres hexadécimaux d’une partie hexadécimale de l’horodatage. Ainsi, même si Math.random est sur la même graine, les deux clients devraient générer l'UUID exactement la même milliseconde (ou 10 000 ans plus tard) pour obtenir le même UUID:

function generateUUID() { // Public Domain/MIT
    var d = new Date().getTime();
    if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
        d += performance.now(); //use high-precision timer if available
    }
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = (d + Math.random() * 16) % 16 | 0;
        d = Math.floor(d / 16);
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
    });
}


Voici un violon à tester.


Pour ceux qui recherchent une solution compatible rfc4122 version 4 avec des considérations de rapidité (quelques appels à Math.random ()):

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

La fonction ci-dessus devrait avoir un bon équilibre entre vitesse et caractère aléatoire.


La meilleure façon:

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
 }

Minimisé:

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}

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

Module JavaScript simple combinant les meilleures réponses dans ce fil.

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

Usage:

Guid.newGuid ()

"c6c2d12f-d76b-5739-e551-07e6de5b0807"

Guid.empty

"00000000-0000-0000-0000-000000000000"


Celui-ci est basé sur la date, et ajoute un suffixe aléatoire pour "assurer" l'unicité. Fonctionne bien pour les identifiants css. Il retourne toujours quelque chose comme et est facile à pirater:

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

La réponse de broofa est plutôt astucieuse: une habileté impressionnante, vraiment ... conforme à la norme rfc4122, assez lisible et compacte. Impressionnant!

Mais si vous regardez cette expression régulière, ces nombreux rappels Math.random() , les appels de fonctions toString() et Math.random() (où il utilise seulement 4 bits du résultat et gaspille le reste), vous pouvez commencer s'interroger sur la performance. En effet, joelpt a même décidé de lancer RFC pour une vitesse GUID générique avec generateQuickGUID .

Mais pouvons-nous obtenir la rapidité et la conformité RFC? Je dis oui! Peut-on maintenir la lisibilité? Eh bien ... Pas vraiment, mais c'est facile si vous suivez.

Mais d’abord, mes résultats, comparés à broofa, guid (la réponse acceptée) et au non-conforme à la rfc, generateQuickGuid :

                  Desktop   Android
           broofa: 1617ms   12869ms
               e1:  636ms    5778ms
               e2:  606ms    4754ms
               e3:  364ms    3003ms
               e4:  329ms    2015ms
               e5:  147ms    1156ms
               e6:  146ms    1035ms
               e7:  105ms     726ms
             guid:  962ms   10762ms
generateQuickGuid:  292ms    2961ms
  - Note: 500k iterations, results will vary by browser/cpu.

Ainsi, à ma sixième 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 à la norme 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:

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

Donc, il remplace x par n'importe quel chiffre hexadécimal aléatoire, y par des données aléatoires (sauf forcer les 2 premiers bits à 10 par la spécification RFC), et la regex ne correspond pas au - ou aux 4 caractères, de sorte qu'il n'a pas à traiter avec eux. Très très lisse.

La première chose à savoir est que les appels de fonction sont coûteux, de même que les expressions régulières (bien qu'il n'en utilise qu'un, 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 la performance consiste à éliminer le RegEx et ses fonctions de rappel et à utiliser une simple boucle. Cela signifie que nous devons composer avec les - et 4 caractères, contrairement à broofa. Notez également que nous pouvons utiliser l'indexation sur tableau de chaînes pour conserver son architecture de modèle de chaîne lisse:

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

Fondamentalement, la même logique interne, sauf que nous vérifions - ou 4 , et l'utilisation d'une boucle while (au lieu de rappels replace() ) nous procure une amélioration presque de 3X!

La prochaine étape est un petit 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 d'en jeter 87% avec un tampon aléatoire décalé à chaque itération. Déplaçons également cette définition de modèle en dehors de la boucle, au cas où cela aiderait:

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
}

Cela nous fait économiser 10-30% selon la plate-forme. Pas mal. Mais la prochaine étape importante consiste à supprimer les appels de la fonction toString avec un classique de l'optimisation - la table de correspondance. Une simple table de correspondance à 16 éléments effectuera le travail de toString (16) en beaucoup moins de temps:

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

La prochaine optimisation est un autre classique. Puisque nous ne gérons que 4 bits de sortie dans chaque itération de boucle, coupons le nombre de boucles en deux et traitons 8 bits à chaque itération. C'est délicat car nous devons toujours gérer les positions de bits conformes à RFC, mais ce n'est pas trop difficile. Nous devons ensuite créer une table de consultation plus grande (16x16 ou 256) pour stocker 0x00 - 0xff et nous ne la construisons qu’une fois, en dehors de la fonction 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
}

J'ai essayé un e6 () qui traite 16 bits à la fois, en utilisant toujours la LUT à 256 éléments, et il a montré les rendements décroissants de l'optimisation. Bien qu’elle ait eu moins d’itérations, la logique interne a été compliquée par l’augmentation du traitement. Elle s’est comportée de la même manière sur les ordinateurs de bureau, et seulement environ 10% plus rapide sur les appareils mobiles.

La technique d'optimisation finale à appliquer - dérouler la boucle. Puisque nous effectuons une boucle un nombre de fois déterminé, nous pouvons techniquement écrire tout cela à la main. J'ai essayé cela une fois avec une seule variable aléatoire r que je réassignais sans cesse, et dont la performance était optimisée. Mais avec quatre variables assignées de manière aléatoire à l’avance, puis en utilisant la table de consultation et en appliquant les bits RFC appropriés, cette version les enfume toutes:

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

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

La chose amusante est que générer 16 octets de données aléatoires est la partie la plus facile. Toute l'astuce consiste à l'exprimer au format String avec conformité RFC, ce qui est 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 véritablement aléatoires, qui sont importants pour générer de bons UUID.


Pour une solution conforme à la norme RFC4122 version 4, cette solution one-liner (ish) est la plus compacte que je puisse RFC4122 :

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

Mise à jour, 2015-06-02 : Sachez que l'unicité des UUID dépend fortement du générateur de nombres aléatoires sous-jacent (GNA). La solution ci-dessus utilise Math.random() par souci de brièveté. Toutefois, Math.random() n’est pas garanti en tant que Math.random() haute qualité. Voir l' excellent article d'Adam Hyland sur Math.random () pour plus de détails. Pour une solution plus robuste, envisagez quelque chose comme le module uuid [Disclaimer: l’auteur], qui utilise des API RNG de meilleure qualité, le cas échéant.

Mise à jour du 26/08/2015 : En résumé , cette gist explique comment déterminer le nombre d'identifiants pouvant être générés avant d'atteindre une certaine probabilité de collision. Par exemple, avec les UUID RFC4122 version 4 3.26x10 15, vous avez 1 chance sur 1 million de collision.

Update, 2017-06-28 : Un bon article de développeurs sur Chrome qui décrit l’état de la qualité PRNG Math.random dans Chrome, Firefox et Safari. tl; dr - À la fin de 2015, la qualité est "plutôt bonne", 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'API de chiffrement et un peu de magicien JS dont je ne peux pas me prévaloir :

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


Un service Web serait utile.

Quick Google trouvé: http://www.hoskinson.net/GuidGenerator/

Vous ne pouvez pas garantir cette implémentation, mais QUELQU'UN doit publier un générateur GUID de bonne foi.

Avec un tel service Web, vous pouvez développer une interface Web REST qui utilise le service Web GUID et la sert via AJAX à JavaScript dans un navigateur.


GUID le plus rapide, comme méthode de génération de chaînes, au format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX . Cela ne génère pas de GUID conforme à la norme.

Dix millions d'exécutions de cette implémentation ne prennent que 32,5 secondes, ce qui est le plus rapide que j'ai jamais vu dans un navigateur (la seule solution sans boucles / itérations).

La fonction est aussi simple que:

/**
 * Generates a GUID string.
 * @returns {String} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser ([email protected]).
 * @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();
}

Pour tester les performances, vous pouvez exécuter ce code:

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

Je suis sûr que la plupart d’entre vous comprendront ce que j’ai fait là-bas, mais peut-être au moins une personne aura-t-elle besoin d’une explication:

L'algorithme:

  • La fonction Math.random() renvoie un nombre décimal compris entre 0 et 1 avec 16 chiffres après le point décimal (par exemple, 0.4363923368509859 ).
  • Ensuite, nous prenons ce nombre et le convertissons en une chaîne de base 16 (à partir de l'exemple ci-dessus, nous aurons 0.6fb7687f ).
    Math.random().toString(16) .
  • Ensuite, nous coupons le préfixe 0. ( 0.6fb7687f => 6fb7687f ) et obtenons une chaîne de huit caractères hexadécimaux.
    (Math.random().toString(16).substr(2,8) .
  • Parfois, la fonction Math.random() retournera un nombre plus court (par exemple, 0.4363 ), en raison de zéros à la fin (d'après l'exemple ci-dessus, le nombre est en 0.4363000000000000 ). C'est pourquoi j'ajoute à cette chaîne "000000000" (une chaîne avec neuf zéros) puis la coupe avec la fonction substr() pour lui donner exactement neuf caractères (les zéros remplis à droite).
  • La raison pour ajouter exactement neuf zéros est due au pire des cas, c'est-à-dire lorsque la fonction Math.random() renverra exactement 0 ou 1 (probabilité de Math.random() ^ 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 (3ème caractère) d'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:

  • Le GUID est au format suivant XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX .
  • J'ai divisé le GUID en 4 morceaux, chaque morceau étant divisé en 2 types (ou formats): XXXXXXXX et -XXXX-XXXX .
  • Maintenant, je construis le GUID en utilisant ces 2 types pour l'assembler avec l'appel de 4 pièces, comme suit: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX .
  • Pour différencier ces deux types, j'ai ajouté un paramètre d'indicateur à une fonction créateur de paire _p8(s) . s paramètre s indique à la fonction s'il faut ajouter des tirets ou non.
  • Finalement, nous construisons le GUID avec le chaînage suivant: _p8() + _p8(true) + _p8(true) + _p8() et le retournons.

Lien vers ce post sur mon blog

Prendre plaisir! :-)


Échantillon ES6

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

Eh bien, cela a déjà un tas de réponses, mais malheureusement, il n’ya pas de "vrai" hasard dans le peloton. 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 chiffrement, le cas échéant, et la fonction Alea () comme solution de secours.

  Math.log2 = Math.log2 || function(n){ return Math.log(n) / Math.log(2); }
  Math.trueRandom = (function() {
  var crypt = window.crypto || window.msCrypto;

  if (crypt && crypt.getRandomValues) {
      // if we have a crypto library, use it
      var random = function(min, max) {
          var rval = 0;
          var range = max - min;
          if (range < 2) {
              return min;
          }

          var bits_needed = Math.ceil(Math.log2(range));
          if (bits_needed > 53) {
            throw new Exception("We cannot generate numbers larger than 53 bits.");
          }
          var bytes_needed = Math.ceil(bits_needed / 8);
          var mask = Math.pow(2, bits_needed) - 1;
          // 7776 -> (2^13 = 8192) -1 == 8191 or 0x00001111 11111111

          // Create byte array and fill with N random numbers
          var byteArray = new Uint8Array(bytes_needed);
          crypt.getRandomValues(byteArray);

          var p = (bytes_needed - 1) * 8;
          for(var i = 0; i < bytes_needed; i++ ) {
              rval += byteArray[i] * Math.pow(2, p);
              p -= 8;
          }

          // Use & to apply the mask and reduce the number of recursive lookups
          rval = rval & mask;

          if (rval >= range) {
              // Integer out of acceptable range
              return random(min, max);
          }
          // Return an integer that falls within the range
          return min + rval;
      }
      return function() {
          var r = random(0, 1000000000) / 1000000000;
          return r;
      };
  } else {
      // From http://baagoe.com/en/RandomMusings/javascript/
      // Johannes Baagøe <[email protected]>, 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 <[email protected]>, 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);
  });
};

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

MODIFIER:

Revisité mon projet qui utilisait cette fonction et n'aimait pas la verbosité. - Mais besoin d'un bon hasard.

Une version basée sur la réponse de Briguy37 et des opérateurs au niveau des bits permettant d'extraire des fenêtres de la taille d'un quartet à partir du tampon.

Devrait adhérer au schéma RFC Type 4 (aléatoire), car la dernière fois que je rencontrais des problèmes, j'analysais des uuids non conformes avec l'UUID de Java.


Ajusté mon propre générateur UUID / GUID avec quelques extras here .

J'utilise le générateur de nombres aléatoires Kybos suivant pour être un peu plus sain sur le plan cryptographique.

Ci-dessous, mon script avec les méthodes Mash et Kybos de baagoe.com est exclu.

//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 <[email protected]>, 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));

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:

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




uuid