Estoy tratando de crear identificadores únicos a nivel mundial en JavaScript. No estoy seguro de qué rutinas están disponibles en todos los navegadores, cuán "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.
javascript
guid
uuid
Jason Cohen
fuente
fuente
Respuestas:
Los UUID (identificador único universal), también conocidos como GUID (identificador único global), de acuerdo con RFC 4122 , son identificadores diseñados para proporcionar ciertas garantías de unicidad.
Si bien es posible implementar un UUID que cumpla con RFC en unas pocas líneas de JS (por ejemplo, vea la respuesta de @ broofa , a continuación), existen varias trampas comunes:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
", donde x es uno de [0-9, af] M es uno de [1-5] y N es [8, 9, a o b]Math.random
)Por lo tanto, se alienta a los desarrolladores que escriben código para entornos de producción a utilizar una implementación rigurosa y bien mantenida, como el módulo uuid .
fuente
Para una solución compatible con RFC4122 versión 4, esta solución de una línea (ish) es la más compacta que se me ocurre:
Actualización, 2015-06-02 : Tenga en cuenta que la unicidad UUID depende en gran medida del generador de números aleatorios (RNG) subyacente. La solución anterior utiliza
Math.random()
por razones de brevedad, sin embargoMath.random()
se no garantiza que sea un generador de números aleatorios de alta calidad. Vea el excelente artículo de Adam Hyland en Math.random () para más detalles. Para una solución más robusta, considere usar el módulo uuid , que usa API RNG de mayor calidad.Actualización, 2015-08-26 : Como nota al margen, este resumen describe cómo determinar cuántas ID se pueden generar antes de alcanzar una cierta probabilidad de colisión. Por ejemplo, con 3.26x10 15 versión 4 RFC4122 UUID tiene una probabilidad de colisión de 1 en un millón.
Actualización, 2017-06-28 : Un buen artículo de desarrolladores de Chrome que discute 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 de calidad criptográfica. Para abordar ese problema, aquí hay una versión actualizada de la solución anterior que usa ES6, la
crypto
API y un poco de la magia JS de la que no puedo dar crédito :Actualización, 2020-01-06 : Hay una propuesta en proceso para un
uuid
módulo estándar como parte del lenguaje JSfuente
c== 'x'
en lugar dec === 'x'
. Porque jshint ha fallado.Realmente me gusta cuán limpia es la respuesta de Broofa , pero es lamentable que las implementaciones deficientes
Math.random
dejen la posibilidad de colisión.Aquí hay una solución similar que cumple con RFC4122 versión 4 que resuelve ese problema al compensar los primeros 13 números hexadecimales por una porción hexadecimal de la marca de tiempo, y una vez agotadas las compensaciones por una porción hexadecimal de los microsegundos desde la carga de la página. De esa manera, incluso si
Math.random
está en la misma semilla, ambos clientes tendrían que generar el UUID exactamente el mismo número de microsegundos desde la carga de la página (si se admite el tiempo de alto rendimiento) Y exactamente en el mismo milisegundo (o más de 10,000 años después) obtener el mismo UUID:Aquí hay un violín para probar.
fuente
new Date().getTime()
que no se actualiza cada milisegundo. No estoy seguro de cómo esto afecta la aleatoriedad esperada de su algoritmo.performance.now()
no están limitadas a una resolución de un milisegundo. En cambio, representan los tiempos como números de punto flotante con una precisión de hasta microsegundos . Además, a diferencia de Date.now, los valores devueltos por performance.now () siempre aumentan a una velocidad constante , independientemente del reloj del sistema, que puede ajustarse manualmente o sesgarse mediante software como el Protocolo de hora de red.d = Math.floor(d/16);
?La respuesta de broofa es bastante hábil, de hecho, impresionantemente inteligente, realmente ... cumple con rfc4122, algo legible y compacto. ¡Increíble!
Pero si está viendo esa expresión regular, esas muchas
replace()
devoluciones de llamada, llamadas de funcióntoString()
yMath.random()
llamadas de función (donde solo usa 4 bits del resultado y desperdicia el resto), puede comenzar a preguntarse sobre el rendimiento. De hecho, joelpt incluso decidió tirar RFC para obtener una velocidad GUID genéricagenerateQuickGUID
.Pero, ¿podemos obtener velocidad y cumplimiento de RFC? ¡Yo digo si! ¿Podemos mantener la legibilidad? Bueno ... En realidad no, pero es fácil si sigues.
Pero primero, mis resultados, en comparación con broofa,
guid
(la respuesta aceptada) y el no compatible con rfcgenerateQuickGuid
:Entonces, en mi sexta iteración de optimizaciones, superé la respuesta más popular en más de 12X , la respuesta aceptada en más de 9X y la respuesta rápida no compatible en 2-3X . Y sigo siendo compatible con rfc4122.
¿Interesado en cómo? Puse la fuente completa en 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:
Por lo tanto, se reemplaza
x
con cualquier dígito hexadecimal aleatorio,y
con datos aleatorios (excepto forzar los 2 bits superiores10
según la especificación RFC), y la expresión regular no coincide con los caracteres-
o4
, 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 caras, 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. toString (16)).
El primer paso hacia el rendimiento es eliminar el RegEx y sus funciones de devolución de llamada y utilizar un bucle simple. Esto significa que tenemos que lidiar con los caracteres
-
y4
mientras que broofa no. Además, tenga en cuenta que podemos usar la indexación de String Array para mantener su elegante arquitectura de plantilla de String:Básicamente, la misma lógica interna, excepto que verificamos
-
o4
, y el uso de un ciclo while (en lugar dereplace()
devoluciones de llamada) nos da una mejora casi 3X.El siguiente paso es pequeño en el escritorio, pero hace una diferencia decente en el móvil. Hagamos menos llamadas Math.random () y utilicemos todos esos bits aleatorios en lugar de tirar el 87% de ellos con un búfer aleatorio que se desplaza en cada iteración. Muevamos también esa definición de plantilla fuera del ciclo, en caso de que ayude:
Esto nos ahorra un 10-30% dependiendo de la plataforma. No está mal. Pero el siguiente gran paso es deshacerse de las llamadas a la función toString con un clásico de optimización: la tabla de búsqueda. Una simple tabla de búsqueda de 16 elementos realizará el trabajo de toString (16) en mucho menos tiempo:
La próxima optimización es otro clásico. Dado que solo estamos manejando 4 bits de salida en cada iteración de bucle, reduzcamos a la mitad el número de bucles y procesemos 8 bits en cada iteración. Esto es complicado ya que todavía tenemos que manejar las posiciones de bits compatibles con RFC, pero no es demasiado difícil. Luego tenemos que hacer una tabla de búsqueda más grande (16x16 o 256) para almacenar 0x00 - 0xff, y la compilamos solo una vez, fuera de la función e5 ().
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 tuvo menos iteraciones, la lógica interna se complicó por el mayor procesamiento, y realizó lo mismo en el escritorio, y solo ~ 10% más rápido en dispositivos móviles.
La técnica de optimización final para aplicar: desenrollar el bucle. Como estamos haciendo un bucle un número fijo de veces, técnicamente podemos escribir todo esto a mano. Intenté esto una vez con una sola variable aleatoria r que seguí reasignando, y el rendimiento se derrumbó. Pero con cuatro variables asignadas datos aleatorios por adelantado, luego usando la tabla de búsqueda y aplicando los bits RFC adecuados, esta versión los fuma a todos:
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 es expresarlo en formato de cadena con cumplimiento de RFC, y se logra 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 este loco viaje a través de la optimización del código!
Tenga en cuenta: 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.
fuente
Math.random()*0xFFFFFFFF
líneas deben serMath.random()*0x100000000
de aleatoriedad total y>>>0
deben usarse en lugar de|0
mantener los valores sin signo (aunque con el código actual creo que se salga bien aunque estén firmados). Finalmente, sería una muy buena idea usar estos díaswindow.crypto.getRandomValues
si está disponible, y recurrir a Math.random solo si es absolutamente necesario. Math.random puede tener menos de 128 bits de entropía, en cuyo caso esto sería más vulnerable a colisiones de lo necesario.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).
fuente
var s = new Array(36);
Mostrar fragmento de código
Si los ID se generan con más de 1 milisegundo de diferencia, son 100% únicos.
Si se generan dos ID a intervalos más cortos, y suponiendo que el método aleatorio es verdaderamente aleatorio, esto generaría ID que son 99.99999999999999% de probabilidad de ser globalmente único (colisión en 1 de 10 ^ 15)
Puede aumentar este número agregando más dígitos, pero para generar un 100% de ID únicos, necesitará usar un contador global.
si necesita compatibilidad con RFC, este formato pasará como un GUID válido de la versión 4:
Mostrar fragmento de código
Editar: El código anterior sigue la intención, pero no la letra del RFC. Entre otras discrepancias, hay unos pocos dígitos aleatorios cortos. (Agregue más dígitos aleatorios si lo necesita) Lo bueno es que esto es realmente rápido :) Puede probar la validez de su GUID aquí
fuente
[slug, date, random].join("_")
para crearusr_1dcn27itd_hj6onj6phr
. Hace que la identificación también se doble como un campo "creado en"El GUID más rápido como método de generador de cadenas en el formato
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
. Esto no genera 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:
Para probar el rendimiento, puede ejecutar este código:
Estoy seguro de que la mayoría de ustedes comprenderá lo que hice allí, pero tal vez haya al menos una persona que necesite una explicación:
El algoritmo:
Math.random()
función devuelve un número decimal entre 0 y 1 con 16 dígitos después del punto de fracción decimal (por ejemplo0.4363923368509859
).0.6fb7687f
).Math.random().toString(16)
.0.
prefijo (0.6fb7687f
=>6fb7687f
) y obtenemos una cadena con ocho caracteres hexadecimales.(Math.random().toString(16).substr(2,8)
.Math.random()
función devolverá un número más corto (por ejemplo0.4363
), debido a ceros al final (del ejemplo anterior, en realidad el número es0.4363000000000000
). Es por eso que agrego a esta cadena"000000000"
(una cadena con nueve ceros) y luego la corto con lasubstr()
función para que tenga nueve caracteres exactamente (llenando ceros a la derecha).Math.random()
función devolverá exactamente 0 o 1 (probabilidad de 1/10 ^ 16 para cada uno de ellos). Es por eso que necesitábamos agregarle nueve ceros ("0"+"000000000"
o"1"+"000000000"
), y luego cortarlo del segundo índice (tercer carácter) con una longitud de ocho caracteres. Para el resto de los casos, la adición de ceros no dañará el resultado porque lo está cortando de todos modos.Math.random().toString(16)+"000000000").substr(2,8)
.La Asamblea:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
.XXXXXXXX
y-XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
, els
parámetro le dice a la función si agregar guiones o no._p8() + _p8(true) + _p8(true) + _p8()
y lo devolvemos.Enlace a esta publicación en mi blog
¡Disfrutar! :-)
fuente
Aquí hay una combinación de la respuesta más votada , con una solución alternativa para las colisiones de Chrome :
En jsbin si quieres probarlo.
fuente
, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` producexxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
.Aquí hay una implementación totalmente no conforme pero muy eficaz para generar un identificador único similar a GUID seguro para ASCII.
Genera 26 caracteres [a-z0-9], produciendo un UID que es más corto y más exclusivo que los GUID compatibles con RFC. Se pueden agregar guiones trivialmente si la legibilidad humana es importante.
Aquí hay ejemplos de uso y tiempos para esta función y varias de las otras respuestas de esta pregunta. El tiempo se realizó bajo Chrome m25, 10 millones de iteraciones cada uno.
Aquí está el código de tiempo.
fuente
Aquí hay una solución fechada el 9 de octubre de 2011 de un comentario del usuario jed en https://gist.github.com/982883 :
Esto logra el mismo objetivo que la respuesta actual mejor calificada , pero en más de 50 bytes menos al explotar la coerción, la recursión y la notación exponencial. Para aquellos curiosos de cómo funciona, aquí está la forma anotada de una versión anterior de la función:
fuente
Del blog técnico de sagi shkedy :
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 nulo.
fuente
Puede usar node-uuid ( https://github.com/kelektiv/node-uuid )
Generación simple y rápida de RFC4122 UUIDS.
caracteristicas:
Instalar usando NPM:
O usando uuid a través del navegador:
Descargar archivo sin formato (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Descargar 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:
ES6:
fuente
EDITAR:
Revisé mi proyecto que estaba usando 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 de tamaño nibble del búfer.
Debería cumplir con el esquema RFC Tipo 4 (aleatorio), ya que la última vez tuve problemas al analizar los uuids no conformes con el UUID de Java.
fuente
Módulo JavaScript simple como una combinación de las mejores respuestas en este hilo.
Uso:
fuente
GUID
comostring
. Su respuesta al menos aborda el almacenamiento mucho más eficiente utilizando aUint16Array
. LatoString
función debería usar la representación binaria en un JavaScriptobject
Esto crea UUID versión 4 (creado a partir de números pseudoaleatorios):
Aquí hay una muestra de los UUID generados:
fuente
Bueno, esto ya tiene un montón de respuestas, pero desafortunadamente no hay un "verdadero" azar en el grupo. La versión a continuación es una adaptación de la respuesta de broofa, pero se actualizó para incluir una función aleatoria "verdadera" que utiliza bibliotecas criptográficas cuando están disponibles, y la función Alea () como alternativa.
fuente
Proyecto JavaScript en GitHub - https://github.com/LiosK/UUID.js
fuente
fuente
Quería entender la respuesta de broofa, así que la amplié y agregué comentarios:
fuente
Ajusté mi propio generador de UUID / GUID con algunos extras aquí .
Estoy usando el siguiente generador de números aleatorios de Kybos para que sea un poco más criptográfico.
A continuación se muestra mi script con los métodos Mash y Kybos de baagoe.com excluidos.
fuente
Para aquellos que desean una solución compatible con rfc4122 versión 4 con consideraciones de velocidad (pocas llamadas a Math.random ()):
La función anterior debe tener un equilibrio decente entre velocidad y aleatoriedad.
fuente
Muestra ES6
fuente
La mejor manera:
Minimizado:
fuente
Lo sé, es una vieja pregunta. Solo 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í:fuente
Este se basa en la fecha y agrega un sufijo aleatorio para "garantizar" la unicidad. Funciona bien para identificadores CSS. Siempre devuelve algo así y es fácil de hackear:
uid-139410573297741
fuente
Código simple que se usa
crypto.getRandomValues(a)
en los navegadores compatibles (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Evita el usoMath.random()
porque eso puede causar colisiones (por ejemplo, 20 colisiones para 4000 líquidos generados en una situación real por Muxa ).Notas:
fuente
Si solo necesita una cadena aleatoria de 128 bits en ningún formato en particular, puede usar:
Lo que devolverá algo así
2350143528-4164020887-938913176-2513998651
.fuente
Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
Solo otra variante más legible con solo dos mutaciones.
fuente
OK, usando el paquete uuid , es compatible con los UUID de las versiones 1, 3, 4 y 5 :
y entonces:
También puede hacerlo con opciones completamente especificadas:
Para obtener más información, visite la página npm aquí.
fuente
Es importante usar un código bien probado que sea mantenido por más de 1 contribuidor en lugar de azotar sus propias cosas para esto. Este es uno de los lugares donde probablemente desee preferir el código más estable que la versión inteligente más corta posible que funcione en el navegador X pero no tenga en cuenta las idiosincrasias de Y, que a menudo conducirían a errores muy difíciles de investigar que se manifiestan al azar para algunos usuarios Personalmente, uso uuid-js en https://github.com/aurigadl/uuid-js que Bower habilitó para poder tomar actualizaciones fácilmente.
fuente