Я пытаюсь создать глобально уникальные идентификаторы в JavaScript. Я не уверен, какие подпрограммы доступны во всех браузерах, насколько «случайным» и затравленным является встроенный генератор случайных чисел и т. Д.
GUID / UUID должен содержать не менее 32 символов и должен оставаться в диапазоне ASCII, чтобы избежать проблем при их передаче.
javascript
guid
uuid
Джейсон Коэн
источник
источник
Ответы:
UUID (универсальный уникальный идентификатор), также известный как GUID (глобальный уникальный идентификатор), согласно RFC 4122 , являются идентификаторами, разработанными для обеспечения определенных гарантий уникальности.
Хотя можно реализовать RFU-совместимые UUID в нескольких строках JS (например, см . Ответ @ broofa , ниже), есть несколько распространенных ошибок:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
", где x - это один из [0-9, af] M - это один из [1-5], а N - [8, 9, a или b].Math.random
)Таким образом, разработчикам, пишущим код для производственных сред, рекомендуется использовать строгую, хорошо поддерживаемую реализацию, такую как модуль uuid .
источник
Для решения, совместимого с RFC4122 версии 4, это однострочное (ish) решение является самым компактным из всех, что я мог придумать:
Обновление, 2015-06-02 : Помните, что уникальность UUID в значительной степени зависит от базового генератора случайных чисел (RNG). Решение выше использует
Math.random()
для краткости, однакоMath.random()
это не гарантированно высокого качества ГСЧ. Посмотрите отличную рецензию Адама Хайленда на Math.random () для подробностей. Для более надежного решения рассмотрите возможность использования модуля uuid , который использует API RNG более высокого качества.Обновление, 2015-08-26 : В качестве побочного сведению, эта сущность описывает , как определить , сколько идентификаторов может быть получена до достижения определенной вероятности столкновения. Например, с 3,26x10 15 UUID RFC4122 версии 4 у вас есть вероятность столкновения 1 на миллион.
Обновление, 2017-06-28 : Хорошая статья от разработчиков Chrome, в которой обсуждается состояние качества PRNG в Math.random в Chrome, Firefox и Safari. tl; dr - По состоянию на конец 2015 года это "довольно хорошо", но не криптографическое качество. Чтобы решить эту проблему, вот обновленная версия вышеупомянутого решения, которая использует ES6,
crypto
API и немного волшебства JS, за которое я не могу взять кредит :Обновление, 2020-01-06 : в работе есть предложение для стандартного
uuid
модуля как части языка JSисточник
c== 'x'
вместоc === 'x'
. Потому что Jshint не удалось.Мне действительно нравится, насколько чист ответ Бруфы , но, к сожалению, плохие реализации
Math.random
оставляют шанс на столкновение.Вот аналогичное решение, соответствующее RFC4122 версии 4, которое решает эту проблему путем смещения первых 13 шестнадцатеричных чисел на шестнадцатеричную часть временной метки и однократного смещения на шестнадцатеричную часть микросекунд с момента загрузки страницы. Таким образом, даже если
Math.random
на одном и том же начальном этапе оба клиента должны будут генерировать UUID с одинаковым количеством микросекунд с момента загрузки страницы (если поддерживается время высокой производительности) И в ту же миллисекунду (или более 10 000 лет спустя) до получить тот же UUID:Вот скрипка для проверки.
источник
new Date().getTime()
не обновляется каждую миллисекунду. Я не уверен, как это влияет на ожидаемую случайность вашего алгоритма.performance.now()
не ограничены разрешением в одну миллисекунду. Вместо этого они представляют время как числа с плавающей точкой с точностью до микросекунды . Кроме того, в отличие от Date.now, значения, возвращаемые performance.now (), всегда увеличиваются с постоянной скоростью , независимо от системных часов, которые можно настраивать вручную или искажать с помощью программного обеспечения, такого как сетевой протокол времени.d = Math.floor(d/16);
?Ответ broofa довольно приятный, действительно - впечатляюще умный, действительно ... rfc4122-совместимый, несколько читабельный и компактный. Потрясающие!
Но если вы посмотрите на это регулярное выражение, эти многочисленные
replace()
обратные вызовыtoString()
иMath.random()
вызовы функций (где он использует только 4 бита результата и тратит впустую все остальное), вы можете задуматься о производительности. Действительно, joelpt даже решил отказаться от RFC для общей скорости GUID сgenerateQuickGUID
.Но можем ли мы получить скорость и соответствие RFC? Я говорю да! Можем ли мы поддерживать читабельность? Ну ... Не совсем, но это легко, если вы будете следовать.
Но сначала мои результаты, по сравнению с бройфой,
guid
(принятый ответ) и несоответствие rfcgenerateQuickGuid
:Итак, моей 6 - й итерации оптимизаций, я бью самый популярный ответ более чем на 12й , Принятый ответ более чем на на 9X , и быстро несоответствующий ответ по 2-3x . И я все еще совместим с rfc4122.
Заинтересованы в том, как? Я поставил полный источник на http://jsfiddle.net/jcward/7hyaC/3/ и на http://jsperf.com/uuid-generator-opt/4
Для объяснения давайте начнем с кода брофы:
Таким образом, он заменяется
x
любой случайной шестнадцатеричной цифройy
со случайными данными (за исключением того, что старшие 2 бита10
соответствуют спецификации RFC), а регулярное выражение не соответствует-
ни4
символам, ни ему, поэтому он не должен иметь с ними дело. Очень, очень гладко.Первое, что нужно знать, это то, что вызовы функций дороги, как и регулярные выражения (хотя он использует только 1, он имеет 32 обратных вызова, по одному на каждое совпадение, и в каждом из 32 обратных вызовов он вызывает Math.random () и v. ToString (16)).
Первым шагом к производительности является устранение RegEx и его функций обратного вызова и использование вместо этого простого цикла. Это означает , что мы должны иметь дело с
-
и4
символов , тогда как broofa не сделал. Также обратите внимание, что мы можем использовать индексирование String Array, чтобы сохранить его простую архитектуру шаблона String:По сути, та же самая внутренняя логика, за исключением того, что мы проверяем на
-
или4
, и используя цикл while (вместоreplace()
обратных вызовов) дает нам почти трехкратное улучшение!Следующим шагом будет небольшой шаг на рабочем столе, но он будет иметь большое значение для мобильных устройств. Давайте сделаем меньше вызовов Math.random () и используем все эти случайные биты вместо того, чтобы выбрасывать 87% из них со случайным буфером, который смещается при каждой итерации. Давайте также уберем это определение шаблона из цикла, на случай, если это поможет:
Это экономит нам 10-30% в зависимости от платформы. Неплохо. Но следующий большой шаг избавляет от вызовов функции toString вместе с классикой оптимизации - справочной таблицей. Простая 16-элементная таблица поиска выполнит работу toString (16) за гораздо меньшее время:
Следующая оптимизация - еще одна классика. Поскольку в каждой итерации цикла мы обрабатываем только 4-битные выходные данные, давайте сократим количество циклов пополам и обработаем 8-битные в каждой итерации. Это сложно, так как нам все еще приходится обрабатывать битовые позиции, соответствующие RFC, но это не слишком сложно. Затем нам нужно создать таблицу поиска большего размера (16x16 или 256) для хранения 0x00 - 0xff, и мы создадим ее только один раз, вне функции e5 ().
Я попробовал e6 (), который обрабатывает 16 бит одновременно, используя LUT из 256 элементов, и он показал убывающую отдачу от оптимизации. Несмотря на меньшее количество итераций, внутренняя логика усложнялась из-за увеличения обработки, и она выполняла то же самое на настольном компьютере и только на ~ 10% быстрее на мобильном устройстве.
Последняя применяемая техника оптимизации - разверните цикл. Поскольку мы зацикливаемся фиксированное количество раз, технически мы можем выписать все это вручную. Я попробовал это однажды с одной случайной переменной r, которую я продолжал переназначать, и производительность снижалась. Но с четырьмя переменными, которым заранее назначены случайные данные, затем с помощью таблицы поиска и применения соответствующих битов RFC, эта версия выкуривает их все:
Модулированный: http://jcward.com/UUID.js -
UUID.generate()
Самое смешное, что генерация 16 байтов случайных данных - самая простая часть. Весь трюк состоит в том, чтобы выразить его в формате String с соблюдением требований RFC, и он наиболее тщательно выполнен с 16 байтами случайных данных, развернутым циклом и таблицей поиска.
Я надеюсь, что моя логика верна - очень легко ошибиться в этом утомительном занятии. Но результаты выглядят хорошо для меня. Надеюсь, вам понравилась эта безумная поездка благодаря оптимизации кода!
Имейте в виду: моей главной целью было показать и научить потенциальных стратегий оптимизации. Другие ответы охватывают важные темы, такие как столкновения и действительно случайные числа, которые важны для создания хороших UUID.
источник
Math.random()*0xFFFFFFFF
строки должны бытьMath.random()*0x100000000
для полной случайности, и>>>0
должны использоваться вместо того,|0
чтобы сохранять значения без знака (хотя с текущим кодом я думаю, что все будет хорошо, даже если они подписаны). Наконец, в наши дни было бы очень хорошей идеей использовать ее,window.crypto.getRandomValues
если она доступна, и возвращаться к Math.random только в случае крайней необходимости. Math.random вполне может иметь менее 128 бит энтропии, и в этом случае это будет более уязвимо для коллизий, чем необходимо.Вот некоторый код, основанный на RFC 4122 , раздел 4.4 (Алгоритмы для создания UUID из действительно случайного или псевдослучайного числа).
источник
var s = new Array(36);
Показать фрагмент кода
Если идентификаторы генерируются с интервалом более 1 миллисекунды, они уникальны на 100%.
Если два идентификатора генерируются с более короткими интервалами и при условии, что случайный метод является действительно случайным, это приведет к созданию идентификаторов, которые с вероятностью 99,999999999999999% будут глобально уникальными (столкновение в 1 из 10 ^ 15)
Вы можете увеличить это число, добавив больше цифр, но для создания 100% уникальных идентификаторов вам потребуется использовать глобальный счетчик.
если вам нужна совместимость с RFC, это форматирование будет считаться действительным GUID версии 4:
Показать фрагмент кода
Изменить: приведенный выше код следуют намерению, но не букве RFC. Среди других несоответствий это несколько случайных цифр. (Добавьте больше случайных цифр, если вам это нужно) Плюс в том, что это действительно быстро :) Вы можете проверить правильность своего GUID здесь
источник
[slug, date, random].join("_")
для созданияusr_1dcn27itd_hj6onj6phr
. Это делает его таким образом, чтобы идентификатор такжеСамый быстрый GUID, как метод строкового генератора в формате
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
. Это не генерирует стандартный GUID.Десять миллионов выполнений этой реализации занимают всего 32,5 секунды, что является самым быстрым, что я когда-либо видел в браузере (единственное решение без циклов / итераций).
Функция так же проста, как:
Чтобы проверить производительность, вы можете запустить этот код:
Я уверен, что большинство из вас поймет, что я там делал, но, возможно, есть хотя бы один человек, которому понадобится объяснение:
Алгоритм:
Math.random()
Функция возвращает десятичное число между 0 и 1 с 16 цифрами после запятой десятичной дроби (например ,0.4363923368509859
).0.6fb7687f
).Math.random().toString(16)
,0.
префикс (0.6fb7687f
=>6fb7687f
) и получаем строку длиной восемь шестнадцатеричных символов.(Math.random().toString(16).substr(2,8)
,Math.random()
функция будет возвращать более короткое число (например0.4363
) из-за нулей в конце (из приведенного выше примера на самом деле это число0.4363000000000000
). Вот почему я добавляю эту строку"000000000"
(строку с девятью нулями), а затем обрезаю ееsubstr()
функции, чтобы сделать ее точно равной девяти символам (заполняя нули справа).Math.random()
функция возвращает ровно 0 или 1 (вероятность 1/10 ^ 16 для каждого из них). Вот почему нам нужно было добавить девять нулей к нему ("0"+"000000000"
или"1"+"000000000"
), а затем отрезать его от второго индекса (3-го символа) длиной восемь символов. В остальных случаях добавление нулей не повредит результату, так как он все равно обрезает его.Math.random().toString(16)+"000000000").substr(2,8)
,Ассамблея:
XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX
.XXXXXXXX
и-XXXX-XXXX
.XXXXXXXX
-XXXX-XXXX
-XXXX-XXXX
XXXXXXXX
._p8(s)
,s
параметр сообщает функции, добавлять ли тире или нет._p8() + _p8(true) + _p8(true) + _p8()
и возвращаем его.Ссылка на этот пост в моем блоге
Наслаждайтесь! :-)
источник
Вот комбинация ответа с наибольшим количеством голосов и обходного пути для столкновений Chrome :
На jsbin, если вы хотите проверить это.
источник
, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of
xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx`, которую она выдаетxxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx
.Вот совершенно несовместимая, но очень производительная реализация для генерации ASCII-безопасного GUID-подобного уникального идентификатора.
Генерирует 26 [a-z0-9] символов, что дает UID, который является одновременно более коротким и уникальным, чем RFID-совместимые GUID. Черточки могут быть тривиально добавлены, если удобочитаемость имеет значение.
Вот примеры использования и время для этой функции и несколько других ответов на этот вопрос. Синхронизация была выполнена под Chrome m25, 10 миллионов итераций каждая.
Вот временный код.
источник
Вот решение от 9 октября 2011 года из комментария пользователя jed на https://gist.github.com/982883 :
Это позволяет достичь той же цели, что и текущий ответ с самым высоким рейтингом , но на 50+ меньше байтов за счет использования приведения, рекурсии и экспоненциальной записи. Для тех, кому интересно, как это работает, вот аннотированная форма старой версии функции:
источник
От технического блога Саги Шкеди :
Есть и другие методы, которые включают использование элемента управления ActiveX, но держитесь подальше от них!
Изменить: Я думал, что стоит отметить, что никакой генератор GUID не может гарантировать уникальные ключи (см. Статью в Википедии ). Всегда есть вероятность столкновения. GUID просто предлагает достаточно большой набор ключей, чтобы свести к минимуму изменение коллизий.
источник
Вы можете использовать node-uuid ( https://github.com/kelektiv/node-uuid )
Простое, быстрое поколение RFC4122 UUIDS.
Особенности:
Установить с помощью NPM:
Или используя uuid через браузер:
Загрузить файл Raw (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Загрузить файл Raw (uuid v4): https://raw.githubusercontent.com/kelektiv/node -uuid / мастер / v4.js
Хотите еще меньше? Проверьте это: https://gist.github.com/jed/982883
Применение:
ES6:
источник
РЕДАКТИРОВАТЬ:
Пересмотрел мой проект, который использовал эту функцию и не понравился многословие. - Но нужна была правильная случайность.
Версия, основанная на ответе Briguy37 и некоторых побитовых операторах для извлечения окон размером с полубайт из буфера.
Следует придерживаться схемы RFC Type 4 (случайная), так как в прошлый раз у меня были проблемы с анализом несовместимых UUID с UUID в Java.
источник
Простой модуль JavaScript как комбинация лучших ответов в этой теме.
Применение:
источник
GUID
какstring
. Ваш ответ, по крайней мере, затрагивает гораздо более эффективное хранилище, используяUint16Array
.toString
Функция должна быть с помощью двоичного представления в JavaScriptobject
Это создает UUID версии 4 (созданный из псевдослучайных чисел):
Вот пример сгенерированных UUID:
источник
Ну, на это уже есть куча ответов, но, к сожалению, в этой группе нет «настоящего» случайного числа. Приведенная ниже версия является адаптацией ответа broofa, но обновлена и теперь включает в себя «истинную» случайную функцию, которая использует криптографические библиотеки, где это возможно, и функцию Alea () в качестве запасного варианта.
источник
Проект JavaScript на GitHub - https://github.com/LiosK/UUID.js
источник
источник
Я хотел понять ответ брофы, поэтому я расширил его и добавил комментарии:
источник
Настроил мой собственный генератор UUID / GUID с некоторыми дополнениями здесь .
Я использую следующие кибос случайных чисел чтобы быть немного более криптографически обоснованным.
Ниже мой сценарий с исключенными методами Mash и Kybos из baagoe.com.
источник
Для тех, кто хочет rfc4122 версии 4 совместимого решения с соображениями скорости (несколько вызовов Math.random ()):
Вышеупомянутая функция должна иметь приличный баланс между скоростью и случайностью.
источник
Образец ES6
источник
Лучший способ:
Минимизация:
источник
Я знаю, это старый вопрос. Просто для полноты, если вашей средой является SharePoint, есть служебная функция
SP.Guid.newGuid
( msdn link ), которая создает новый guid. Эта функция находится внутри файла sp.init.js. Если вы переписываете эту функцию (чтобы удалить некоторые другие зависимости от других закрытых функций), она выглядит так:источник
Этот основан на дате и добавляет случайный суффикс для «обеспечения» уникальности. Хорошо работает для идентификаторов CSS. Он всегда возвращает что-то вроде и его легко взломать:
UID-139410573297741
источник
Простой код, который используется
crypto.getRandomValues(a)
в поддерживаемых браузерах (IE11 +, iOS7 +, FF21 +, Chrome, Android Chrome). Избегает использования,Math.random()
потому что это может вызвать столкновения (например, 20 столкновений для 4000 сгенерированных uuids в реальной ситуации Muxa ).Ноты:
источник
Если вам просто нужна случайная 128-битная строка без определенного формата, вы можете использовать:
Который вернет что-то вроде
2350143528-4164020887-938913176-2513998651
.источник
Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')
Просто еще один более читаемый вариант с двумя мутациями.
источник
Хорошо, используя пакет uuid , поддержка UUID версий 1, 3, 4 и 5 :
а потом:
Вы также можете сделать это с помощью полностью указанных опций:
Для получения дополнительной информации посетите страницу npm здесь
источник
Важно использовать хорошо протестированный код, который поддерживается более чем 1 участником, вместо того, чтобы использовать для этого свой собственный материал. Это одно из тех мест, где вы, вероятно, хотите отдать предпочтение наиболее стабильному коду, а не самой короткой из возможных умных версий, которые работают в браузере X, но не учитывают идиосинкразии Y, которые часто приводят к очень трудным исследованиям ошибок, а не случайным образом. для некоторых пользователей. Лично я использую uuid-js по адресу https://github.com/aurigadl/uuid-js, в котором включена функция bower, чтобы я мог легко получать обновления.
источник