Pregunta

Estoy intentando crear identificadores únicos a nivel mundial en JavaScript.No estoy seguro de qué rutinas están disponibles en todos los navegadores, qué tan "aleatorio" y sembrado es el generador de números aleatorios incorporado, etc.

El GUID/UUID debe tener al menos 32 caracteres y debe permanecer en el rango ASCII para evitar problemas al pasarlos.

¿Fue útil?

Solución

UUID (Universally Unique IDentifier), también conocidos como GUID (Globally Unique IDentifier), según RFC 4122, son identificadores con cierta garantía de unicidad.

La mejor manera de generarlos es seguir las instrucciones de implementación en dicho RFC y utilizar una de las muchas implementaciones de código abierto examinadas por la comunidad.

Una herramienta popular de código abierto para trabajar con UUID en JavaScript es nodo-uuid

Tenga en cuenta que generar aleatoriamente los identificadores byte a byte o carácter a carácter no le dará las mismas garantías que una implementación conforme.Además, es muy importante que los sistemas que trabajan con UUID compatibles puedan optar por no aceptar los generados aleatoriamente, y muchos validadores de código abierto comprobarán si hay una estructura válida.

Un UUID debe tener este formato:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Donde el METRO y norte las posiciones solo pueden tener ciertos valores.En este momento, los únicos valores válidos para M son 1, 2, 3, 4 y 5, por lo que generar esa posición aleatoriamente haría que la mayoría de los resultados fueran inaceptables.

Otros consejos

Por un RFC4122 Solución compatible con la versión 4, esta solución de una sola línea (más o menos) es la más compacta que se me ocurrió:

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

Actualización, 2015-06-02:Tenga en cuenta que la unicidad del UUID depende en gran medida del generador de números aleatorios (RNG) subyacente.La solución anterior utiliza Math.random() por brevedad, sin embargo Math.random() es no Garantizado como un RNG de alta calidad.Ver Adam Hyland excelente artículo sobre Math.random() para detalles.Para una solución más sólida, considere algo como el módulo uuid[Descargo de responsabilidad:Soy el autor], que utiliza API RNG de mayor calidad cuando estén disponibles.

Actualización, 2015-08-26:Como nota al margen, esto esencia describe cómo determinar cuántas ID se pueden generar antes de alcanzar una cierta probabilidad de colisión.Por ejemplo, con 3,26x1015 UUID RFC4122 de la versión 4, tiene una probabilidad de colisión de 1 entre un millón.

Actualización, 2017-06-28:A buen artículo de los desarrolladores de Chrome analizando el estado de la calidad de Math.random PRNG en Chrome, Firefox y Safari.tl;dr: a finales de 2015 es "bastante bueno", pero no tiene calidad criptográfica.Para solucionar ese problema, aquí hay una versión actualizada de la solución anterior que utiliza ES6, el crypto API y un poco de magia de JS por la que no puedo atribuirme el mérito:

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

Me gusta mucho lo limpio La respuesta de Broofa lo es, pero es desafortunado que las malas implementaciones de Math.random Deja la posibilidad de colisión.

Aquí hay uno similar RFC4122 Solución compatible con la versión 4 que resuelve ese problema compensando los primeros 13 números hexadecimales por una porción hexadecimal de la marca de tiempo.De esa manera, incluso si Math.random está en la misma semilla, ambos clientes tendrían que generar el UUID exactamente en el mismo milisegundo (o más de 10,000 años después) para obtener el mismo 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);
    });
}


Aquí tienes un violín para probar.

La respuesta de broofa es bastante hábil, de hecho: impresionantemente inteligente, de verdad...Compatible con rfc4122, algo legible y compacto.¡Impresionante!

Pero si nos fijamos en esa expresión regular, esas muchas replace() devoluciones de llamada, toString()'arena Math.random() llamadas a funciones (donde solo usa 4 bits del resultado y desperdicia el resto), puede comenzar a preguntarse sobre el rendimiento.De hecho, joelpt incluso decidió descartar RFC por velocidad GUID genérica con generateQuickGUID.

Pero, ¿podemos conseguir velocidad? y ¿Cumplimiento de RFC?¡Yo digo si! ¿Podemos mantener la legibilidad?Bien...En realidad no, pero es fácil si lo sigues.

Pero primero, mis resultados, en comparación con broofa, guid (la respuesta aceptada) y la que no cumple con 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.

Entonces, en mi sexta iteración de optimizaciones, superé la respuesta más popular por más de 12X, la respuesta aceptada por más 9X, y la respuesta rápida de incumplimiento por 2-3X.Y sigo cumpliendo con rfc4122.

¿Interesado en cómo?He puesto la fuente completa http://jsfiddle.net/jcward/7hyaC/3/ y en http://jsperf.com/uuid-generator-opt/4

Para una explicación, comencemos con el código 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);
});

Entonces reemplaza x con cualquier dígito hexadecimal aleatorio, y con datos aleatorios (excepto obligar a los 2 bits superiores a 10 según la especificación RFC), y la expresión regular no coincide con la - o 4 personajes, por lo que no tiene que lidiar con ellos.Muy, muy hábil.

Lo primero que debe saber es que las llamadas a funciones son costosas, al igual que las expresiones regulares (aunque solo usa 1, tiene 32 devoluciones de llamada, una para cada coincidencia, y en cada una de las 32 devoluciones de llamada llama a Math.random() y v. a Cadena (16)).

El primer paso hacia el rendimiento es eliminar RegEx y sus funciones de devolución de llamada y utilizar un bucle simple en su lugar.Esto significa que tenemos que lidiar con el - y 4 personajes mientras que broofa no lo hizo.Además, tenga en cuenta que podemos usar la indexación de String Array para mantener su elegante arquitectura de plantilla de String:

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

Básicamente, la misma lógica interna, excepto que verificamos - o 4, y usando un bucle while (en lugar de replace() devoluciones de llamada) ¡nos brinda una mejora de casi 3 veces!

El siguiente paso es pequeño en el escritorio, pero marca una diferencia decente en el móvil.Hagamos menos llamadas a Math.random() y utilicemos todos esos bits aleatorios en lugar de desechar el 87% de ellos con un búfer aleatorio que se desplaza en cada iteración.También saquemos la definición de plantilla del ciclo, por si acaso ayuda:

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
}

Esto nos ahorra entre un 10 y un 30% según la plataforma.Nada mal.Pero el siguiente gran paso elimina por completo las llamadas a la función toString con un clásico de optimización: la tabla de búsqueda.Una tabla de búsqueda simple de 16 elementos realizará el trabajo de toString(16) en mucho menos tiempo:

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 siguiente optimización es otro clásico.Dado que solo manejamos 4 bits de salida en cada iteración del bucle, reduzcamos el número de bucles a la mitad y procesemos 8 bits en cada iteración.Esto es complicado ya que todavía tenemos que manejar las posiciones de bits que cumplen con RFC, pero no es demasiado difícil.Luego tenemos que crear una tabla de búsqueda más grande (16x16 o 256) para almacenar 0x00 - 0xff, y la construimos solo una vez, fuera de la función 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
}

Probé un e6() que procesa 16 bits a la vez, todavía usando la LUT de 256 elementos, y mostró los rendimientos decrecientes de la optimización.Aunque tenía menos iteraciones, la lógica interna se complicaba por el mayor procesamiento y funcionaba igual en el escritorio, y solo ~10% más rápido en el móvil.

La última técnica de optimización a aplicar es desenrollar el bucle.Dado que estamos repitiendo un número fijo de veces, técnicamente podemos escribir todo esto a mano.Intenté esto una vez con una única variable aleatoria r que seguí reasignando y el rendimiento se desplomó.Pero con cuatro variables asignadas datos aleatorios desde el principio, luego usando la tabla de búsqueda y aplicando los bits RFC adecuados, esta versión los elimina a todos:

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

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

Lo curioso es que generar 16 bytes de datos aleatorios es la parte fácil.Todo el truco consiste en expresarlo en formato String que cumpla con RFC, y se logra mejor con 16 bytes de datos aleatorios, un bucle desenrollado y una tabla de búsqueda.

Espero que mi lógica sea correcta: es muy fácil cometer un error en este tipo de trabajo tedioso.Pero los resultados me parecen buenos.¡Espero que hayas disfrutado de este loco viaje a través de la optimización del código!

Ser aconsejado: Mi objetivo principal era mostrar y enseñar posibles estrategias de optimización.Otras respuestas cubren temas importantes como colisiones y números verdaderamente aleatorios, que son importantes para generar buenos UUID.

Aquí hay un código basado en RFC 4122, sección 4.4 (Algoritmos para crear un UUID a partir de un número verdaderamente aleatorio o pseudoaleatorio).

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;
}
var uniqueId = Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);

Si los ID se generan con más de 1 milisegundo de diferencia, son 100% únicos.

Si se generan dos ID en intervalos más cortos, y suponiendo que el método aleatorio es verdaderamente aleatorio, esto generaría ID que tienen un 99,999999999999999% de probabilidad de ser globalmente únicas (colisión en 1 de 10^15).

Puede aumentar este número agregando más dígitos, pero para generar identificaciones 100% únicas necesitará usar un contador global.

Si realmente necesita cumplir con RFC, este formato se considerará un GUID de versión 4 válido:

const uid = (new Date()).getTime().toString(16) + Math.random().toString(16).substring(2) + "0".repeat(16);
const guid = uid.substr(0,8) + '-' + uid.substr(8,4) + '-4000-8' + uid.substr(12,3) + '-' + uid.substr(15,12);

Editar:El código anterior sigue la intención, pero no la letra del RFC.Entre otras discrepancias, le faltan unos pocos dígitos aleatorios.(Agregue más dígitos aleatorios si lo necesita) La ventaja es que esto es realmente rápido, en comparación con el código 100% compatible.Puede prueba tu GUID aquí

GUID más rápido como método generador de cadenas en el formato XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.Esto no genera un GUID compatible con el estándar.

Diez millones de ejecuciones de esta implementación toman solo 32,5 segundos, que es lo más rápido que he visto en un navegador (la única solución sin bucles/iteraciones).

La función es tan simple como:

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

Para probar el rendimiento, puede ejecutar este código:

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

Estoy seguro de que la mayoría de ustedes entenderán lo que hice allí, pero tal vez haya al menos una persona que necesite una explicación:

El algoritmo:

  • El Math.random() La función devuelve un número decimal entre 0 y 1 con 16 dígitos después del punto de fracción decimal (por ejemplo 0.4363923368509859).
  • Luego tomamos este número y lo convirtimos en una cadena con la base 16 (del ejemplo anterior obtendremos0.6fb7687f).
    Math.random().toString(16).
  • Luego cortamos el 0. prefijo (0.6fb7687f => 6fb7687f) y obtenga una cadena con ocho caracteres hexadecimales de largo.
    (Math.random().toString(16).substr(2,8).
  • A veces el Math.random() la función devolverá un número más corto (por ejemplo 0.4363), debido a los ceros al final (del ejemplo anterior, en realidad el número es 0.4363000000000000).Es por eso que estoy agregando a esta cadena "000000000" (una cuerda con nueve ceros) y luego cortándola con substr() función para que sean nueve caracteres exactamente (llenando ceros a la derecha).
  • La razón para agregar exactamente nueve ceros es por el peor de los casos, que es cuando el Math.random() La función devolverá exactamente 0 o 1 (probabilidad de 1/10^16 para cada uno de ellos).Por eso necesitábamos agregarle nueve ceros ("0"+"000000000" o "1"+"000000000"), y luego cortándolo del segundo índice (tercer carácter) con una longitud de ocho caracteres.Para el resto de casos, la adición de ceros no perjudicará el resultado porque de todos modos lo está truncando.
    Math.random().toString(16)+"000000000").substr(2,8).

La Asamblea:

  • El GUID tiene el siguiente formato. XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • Dividí el GUID en 4 partes, cada parte dividida en 2 tipos (o formatos): XXXXXXXX y -XXXX-XXXX.
  • Ahora estoy construyendo el GUID usando estos 2 tipos para ensamblar el GUID con llamadas de 4 piezas, de la siguiente manera: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Para diferenciar entre estos dos tipos, agregué un parámetro de bandera a una función de creación de pares. _p8(s), el s El parámetro le dice a la función si agregar guiones o no.
  • Finalmente construimos el GUID con el siguiente encadenamiento: _p8() + _p8(true) + _p8(true) + _p8(), y devuélvelo.

Enlace a esta entrada en mi blog.

¡Disfrutar!:-)

Aquí hay una combinación de respuesta más votada, con una solución para Las colisiones de Chrome:

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // https://stackoverflow.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://stackoverflow.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);
        });
    };

en jsbin si quieres probarlo.

Aquí hay una implementación totalmente no compatible pero muy eficaz para generar un identificador único tipo GUID seguro para ASCII.

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

Genera 26 [a-z0-9] caracteres, lo que produce un UID que es más corto y más exclusivo que los GUID compatibles con RFC.Los guiones se pueden agregar de manera trivial si la legibilidad humana es importante.

A continuación se muestran ejemplos de uso y tiempos para esta función y varias de las otras respuestas de esta pregunta.El cronometraje se realizó en Chrome m25, 10 millones de iteraciones cada una.

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

Aquí está el código de tiempo.

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

Aquí hay una solución con fecha de octubre.9, 2011 a partir de un comentario de usuario. jed en 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)}

Esto logra el mismo objetivo que el respuesta actual mejor calificada, pero en más de 50 bytes menos mediante la explotación de la coerción, la recursividad y la notación exponencial.Para aquellos que tengan curiosidad sobre cómo funciona, aquí está la forma comentada de una versión anterior de la función:

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

De blog técnico 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;
}

Existen otros métodos que implican el uso de un control ActiveX, ¡pero manténgase alejado de estos!

Editar : Pensé que valía la pena señalar que ningún generador de GUID puede garantizar claves únicas (consulte el artículo de wikipedia).Siempre existe la posibilidad de colisiones.Un GUID simplemente ofrece un universo de claves lo suficientemente grande como para reducir el cambio de colisiones a casi cero.

Puedes usar nodo-uuid (https://github.com/kelektiv/node-uuid)

Generación sencilla y rápida de RFC4122 UUID.

Características:

  • Generar UUID RFC4122 versión 1 o versión 4
  • Se ejecuta en node.js y navegadores.
  • Generación # aleatoria criptográficamente fuerte en plataformas de soporte.
  • Tamaño reducido (¿Quieres algo más pequeño? ¡Mira esto!)

Instalar usando NPM:

npm install uuid

O usando uuid a través del navegador:

Descargar archivo sin formato (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.jsDescargar archivo sin formato (uuid v4): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js


¿Quieres aún más pequeño?Mira esto: https://gist.github.com/jed/982883


Uso:

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

Un servicio web sería útil.

Búsqueda rápida de Google: http://www.hoskinson.net/GuidGenerator/

No puedo garantizar esta implementación, pero ALGUIEN debe publicar un generador GUID auténtico.

Con un servicio web de este tipo, podría desarrollar una interfaz web REST que consuma el servicio web GUID y lo proporcione a través de AJAX a javascript en un navegador.

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

EDITAR:

Revisé mi proyecto que usaba esta función y no me gustó la verbosidad.- Pero necesitaba una aleatoriedad adecuada.

Una versión basada en la respuesta de Briguy37 y algunos operadores bit a bit para extraer ventanas del tamaño de un bocado del búfer.

Debería cumplir con el esquema RFC Tipo 4 (aleatorio), ya que la última vez tuve problemas al analizar uuids no compatibles con el UUID de Java.

Módulo JavaScript simple como una combinación de las mejores respuestas en este hilo.

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

Uso:

Guid.newGuid()

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

Guid.vacío

"00000000-0000-0000-0000-000000000000"

De buena y vieja wikipedia hay un enlace a una implementación javascript de UUID.

Parece bastante elegante y tal vez podría mejorarse añadiendo un hash de la dirección IP del cliente.Este hash quizás podría insertarse en el lado del servidor del documento html para que lo utilice el javascript del lado del cliente.

ACTUALIZAR :El sitio original ha tenido cambios, aquí está el Versión actualizada

Bueno, esto ya tiene un montón de respuestas, pero desafortunadamente no hay una "verdadera" aleatoria entre todas.La siguiente versión es una adaptación de la respuesta de broofa, pero actualizada para incluir una función aleatoria "verdadera" que utiliza bibliotecas criptográficas cuando estén disponibles, y la función Alea() como alternativa.

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

Esto crea la versión 4 del UUID (creado a partir de números pseudoaleatorios):

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

Aquí hay una muestra de los UUID generados:

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

Proyecto JavaScript en GitHub - https://github.com/LiosK/UUID.js

UUID.js El generador de UUID compatible con RFC para JavaScript.

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

Características Genera UUID compatibles con RFC 4122.

La versión 4 de UUID (UUID de números aleatorios) y UUID de la versión 1 (UUID basados ​​en el tiempo) están disponibles.

El objeto UUID permite una variedad de acceso al UUID, incluido el acceso a los campos UUID.

La baja resolución de la marca de tiempo de JavaScript es compensada por números aleatorios.

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

Ajusté mi propio generador de UUID/GUID con algunos extras aquí.

Estoy usando los siguientes Kybos generador de números aleatorios para que sea un poco más sólido criptográficamente.

A continuación se muestra mi script con los métodos Mash y Kybos de baagoe.com excluidos.

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

La mejor manera:

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
 }

Minimizado:

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}

Quería entender la respuesta de broofa, así que la amplié y agregué comentarios:

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

muestra ES6

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

Es sólo una simple llamada AJAX...

Si alguien todavía está interesado, aquí está mi solución.

Del lado del servidor:

[WebMethod()]
public static string GenerateGuid()
{
    return Guid.NewGuid().ToString();
}

Del lado del cliente:

var myNewGuid = null;
PageMethods.GenerateGuid(
    function(result, userContext, methodName)
    {
        myNewGuid = result;
    },
    function()
    {
        alert("WebService call failed.");
    }
);

Para aquellos que desean una solución compatible con rfc4122 versión 4 con consideraciones de velocidad (algunas llamadas a 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 función anterior debería tener un equilibrio decente entre velocidad y aleatoriedad.

Este se basa en la fecha y agrega un sufijo aleatorio para "garantizar" la singularidad.Funciona bien para identificadores CSS.Siempre devuelve algo como y es fácil de hackear:

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

Lo sé, es una vieja pregunta.Para completar, si su entorno es SharePoint, hay una función de utilidad llamada SP.Guid.newGuid (enlace msdn) que crea una nueva guía.Esta función está dentro del archivo sp.init.js.Si reescribe esta función (para eliminar algunas otras dependencias de otras funciones privadas), se verá así:

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

Hay un complemento jQuery que maneja muy bien @ de Guid http://plugins.jquery.com/project/GUID_Helper

jQuery.Guid.Value()

Devuelve el valor del Guid interno.Si no se ha especificado ningún guid, devuelve uno nuevo (el valor se almacena internamente).


jQuery.Guid.New()

Devuelve un nuevo Guid y establece su valor internamente.


jQuery.Guid.Empty()

Devuelve un Guid vacío 00000000-0000-0000-0000-000000000000.


jQuery.Guid.IsEmpty()

Devuelve booleano.Verdadero si está vacío/indefinido/en blanco/nulo.


jQuery.Guid.IsValid()

Devuelve booleano.Verdadera guía válida, falsa si no.


jQuery.Guid.Set()

Guía de retornos.Establece Guid en el Guid especificado por el usuario; si no es válido, devuelve un guid vacío.

Código simple que utiliza crypto.getRandomValues(a) en navegadores compatibles (IE11+, iOS7+, FF21+, Chrome, Android Chrome).Evita usar Math.random() porque eso puede causar colisiones (por ejemplo, 20 colisiones para 4000 uuids generados en una situación real por muxá).

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

Notas:

  • Optimizado para la legibilidad del código, no para la velocidad, por lo que es adecuado para, digamos, unos cientos de uuid por segundo.Genera alrededor de 10000 uuid() por segundo en Chromium en mi computadora portátil usando http://jsbin.com/fuwigo/1 para medir el desempeño.
  • Solo usa 8 para "y" porque eso simplifica la legibilidad del código (se permite que y sea 8, 9, A o B).
Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top