Вопрос

Я пытаюсь создать глобально уникальные идентификаторы в JavaScript.Я не уверен, какие процедуры доступны во всех браузерах, насколько "случайным" является встроенный генератор случайных чисел и т.д..

GUID / UUID должен содержать не менее 32 символов и должен оставаться в диапазоне ASCII, чтобы избежать проблем при их передаче.

Это было полезно?

Решение

UUIDs (Универсально уникальный идентификатор), также известный как GUIDs (глобально уникальный идентификатор), в соответствии с RFC 4122, являются идентификаторами с определенной гарантией уникальности.

Лучший способ сгенерировать их - следовать инструкциям по реализации в упомянутом RFC, использовать одну из многих проверенных сообществом реализаций с открытым исходным кодом.

Популярным инструментом с открытым исходным кодом для работы с UUID в JavaScript является узел-uuid

Обратите внимание, что простая случайная генерация идентификаторов байт за байтом или символ за символом не даст вам тех же гарантий, что и соответствующая реализация.Кроме того, что очень важно, системы, работающие с совместимыми UUID, могут отказаться от приема случайно сгенерированных идентификаторов, и многие валидаторы с открытым исходным кодом фактически проверят допустимую структуру.

UUID должен иметь такой формат:

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

Где находится M и N позиции могут иметь только определенные значения.На данный момент единственными допустимыми значениями для M являются 1, 2, 3, 4 и 5, поэтому случайная генерация этой позиции сделала бы большинство результатов неприемлемыми.

Другие советы

Для RFC4122 совместимое с версией 4 решение, это однострочное решение является самым компактным, которое я смог придумать.:

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

Обновление, 2015-06-02:Имейте в виду, что уникальность UUID в значительной степени зависит от базового генератора случайных чисел (RNG).Приведенное выше решение использует Math.random() однако для краткости Math.random() является нет гарантировано, что это будет высококачественный ГСЧ.Посмотрите фильм Адама Хайланда отличная работа по математике.random() за подробностями.Для более надежного решения рассмотрим что-то вроде модуль uuid[Отказ от ответственности:Я автор], который использует API-интерфейсы RNG более высокого качества там, где это доступно.

Обновление, 2015-08-26:В качестве дополнительного примечания, это суть описывает, как определить, сколько идентификаторов может быть сгенерировано до достижения определенной вероятности столкновения.Например, с размером 3.26x1015 UUIDs версии 4 RFC4122 у вас есть шанс столкновения 1 к миллиону.

Обновление, 2017-06-28:A хорошая статья от разработчиков Chrome обсуждаем состояние качества Math.random PRNG в Chrome, Firefox и Safari.tl; dr - По состоянию на конец 2015 года это "довольно хорошее", но не криптографическое качество.Чтобы решить эту проблему, вот обновленная версия вышеупомянутого решения, которое использует ES6, crypto API, и немного JS wizardy, за которое я не могу поставить себе в заслугу:

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

Мне действительно нравится, как чисто Ответ Бруфы есть, но, к сожалению, плохая реализация Math.random оставьте возможность столкновения.

Вот похожий RFC4122 совместимое с версией 4 решение, которое решает эту проблему путем смещения первых 13 шестнадцатеричных чисел на шестнадцатеричную часть временной метки.Таким образом, даже если Math.random если используется одно и то же начальное значение, оба клиента должны были бы сгенерировать UUID в одну и ту же миллисекунду (или более чем через 10 000 лет), чтобы получить один и тот же 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);
    });
}


Вот скрипка для тестирования.

ответ бруфы действительно довольно ловкий - впечатляюще умный, на самом деле...совместимый с rfc4122, в некоторой степени читаемый и компактный.Потрясающе!

Но если вы посмотрите на это регулярное выражение, то эти многие replace() обратные вызовы, toString()'s и Math.random() вызовы функций (где он использует только 4 бита результата, а остальное тратит впустую), вы можете начать задаваться вопросом о производительности.Действительно, joelpt даже решил отказаться от RFC для повышения скорости использования универсального GUID с generateQuickGUID.

Но можем ли мы ускорить процесс и Соответствие RFC?Я говорю, ДА! Можем ли мы сохранить удобочитаемость?Что ж...Не совсем, но это легко, если вы будете следовать за мной.

Но сначала мои результаты по сравнению с broofa, guid (принятый ответ), и несоответствующий 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.

Итак, к моей 6-й итерации оптимизации я превзошел самый популярный ответ более чем на 12X, принятый ответ более чем 9X, и быстрый несоответствующий ответ от 2-3X.И я по-прежнему соответствую стандарту rfc4122.

Интересно, каким образом?Я включил полный исходный код http://jsfiddle.net/jcward/7hyaC/3/ и дальше http://jsperf.com/uuid-generator-opt/4

Для пояснения давайте начнем с кода 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);
});

Таким образом, он заменяет x с любой случайной шестнадцатеричной цифрой, y со случайными данными (за исключением принудительного ввода 2-х верхних битов в 10 согласно спецификации RFC), и регулярное выражение не соответствует - или 4 персонажи, так что ему не приходится иметь с ними дело.Очень, очень ловко.

Первое, что нужно знать, это то, что вызовы функций стоят дорого, как и регулярные выражения (хотя он использует только 1, у него 32 обратных вызова, по одному для каждого совпадения, и в каждом из 32 обратных вызовов он вызывает Math.random() и v.toString(16)).

Первый шаг к повышению производительности - исключить регулярное выражение и его функции обратного вызова и использовать вместо него простой цикл.Это означает, что мы должны иметь дело с - и 4 персонажи, в то время как бруфа этого не сделал.Также обратите внимание, что мы можем использовать индексацию массива строк, чтобы сохранить его гладкую архитектуру шаблона 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;
}

По сути, та же внутренняя логика, за исключением того, что мы проверяем наличие - или 4, и используя цикл while (вместо replace() обратные вызовы) улучшают качество почти в 3 раза!

Следующий шаг невелик для настольных компьютеров, но имеет существенное значение для мобильных устройств.Давайте сделаем меньше вызовов Math.random() и будем использовать все эти случайные биты вместо того, чтобы выбрасывать 87% из них с помощью случайного буфера, который смещается с каждой итерацией.Давайте также уберем это определение шаблона из цикла, на всякий случай, если это поможет:

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
}

Это экономит нам 10-30% в зависимости от платформы.Неплохо.Но следующий важный шаг позволяет полностью избавиться от вызовов функции toString с помощью классического метода оптимизации - справочной таблицы.Простая таблица подстановки из 16 элементов выполнит задачу toString(16) за гораздо меньшее время:

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
}

Следующая оптимизация - это еще одна классика.Поскольку мы обрабатываем только 4 бита выходных данных на каждой итерации цикла, давайте сократим количество циклов вдвое и будем обрабатывать 8 бит на каждой итерации.Это сложно, поскольку нам все еще приходится обрабатывать битовые позиции, совместимые с RFC, но это не слишком сложно.Затем нам нужно создать таблицу подстановки большего размера (16x16 или 256) для хранения 0x00 - 0xff, и мы создаем ее только один раз, вне функции 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
}

Я попробовал e6(), который обрабатывает 16 бит за раз, все еще используя LUT из 256 элементов, и он показал уменьшающуюся отдачу от оптимизации.Хотя в нем было меньше итераций, внутренняя логика усложнялась из-за увеличения объема обработки, и он выполнял то же самое на настольных компьютерах и только на ~ 10% быстрее на мобильных устройствах.

Последний метод оптимизации, который нужно применить - размотать цикл.Поскольку мы выполняем цикл фиксированное количество раз, технически мы можем записать все это от руки.Я попробовал это однажды с одной случайной величиной r, которую постоянно переназначал, и производительность упала.Но с четырьмя переменными, которым заранее назначены случайные данные, затем с использованием таблицы подстановки и применением соответствующих битов RFC, эта версия удаляет их все:

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

Модифицированный: http://jcward.com/UUID.js - UUID.generate()

Самое смешное, что сгенерировать 16 байт случайных данных - это самая простая часть.Весь фокус в том, чтобы выразить это в строковом формате, соответствующем RFC, и наиболее точно это достигается с помощью 16 байт случайных данных, развернутого цикла и таблицы подстановки.

Я надеюсь, что моя логика верна - в такой утомительной работе очень легко допустить ошибку.Но результаты, на мой взгляд, выглядят неплохо.Я надеюсь, вам понравилась эта безумная поездка по оптимизации кода!

Имейте в виду: моей основной целью было показать и научить потенциальным стратегиям оптимизации.Другие ответы охватывают важные темы, такие как коллизии и действительно случайные числа, которые важны для генерации хороших UUID.

Вот некоторый код, основанный на RFC 4122, раздел 4.4 (Алгоритмы создания UUID из действительно случайного или псевдослучайного числа).

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

Если идентификаторы генерируются с интервалом более 1 миллисекунды, они уникальны на 100%.

Если два идентификатора генерируются с более короткими интервалами и предполагается, что случайный метод действительно случайный, это приведет к генерации идентификаторов, которые с вероятностью 99,99999999999999% будут глобально уникальными (столкновение в 1 из 10 ^ 15)

Вы можете увеличить это число, добавив больше цифр, но для генерации 100% уникальных идентификаторов вам нужно будет использовать глобальный счетчик.

если вам действительно нужно соответствие RFC, это форматирование будет передано как действительный GUID версии 4:

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

Редактировать:Приведенный выше код соответствует намерению, но не букве RFC.Среди прочих расхождений - не хватает нескольких случайных цифр.(Добавьте больше случайных цифр, если вам это нужно) Положительным моментом является то, что это действительно быстро по сравнению со 100% совместимым кодом.Ты можешь проверьте свой GUID здесь

Самый быстрый метод генерации строк, подобный GUID, в формате XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.При этом не генерируется соответствующий стандарту GUID.

Десять миллионов запусков этой реализации занимают всего 32,5 секунды, что является самым быстрым, что я когда-либо видел в браузере (единственное решение без циклов / итераций).

Эта функция так же проста, как:

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

Чтобы проверить производительность, вы можете запустить этот код:

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

Я уверен, что большинство из вас поймут, что я там сделал, но, возможно, найдется хотя бы один человек, которому потребуется объяснение:

Алгоритм:

  • Тот Самый Math.random() функция возвращает десятичное число от 0 до 1 с 16 цифрами после запятой (для примера 0.4363923368509859).
  • Затем мы берем это число и преобразуем его в строку с основанием 16 (из приведенного выше примера мы получим 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).

Собрание:

  • Идентификатор GUID представлен в следующем формате XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • Я разделил GUID на 4 части, каждая часть разделена на 2 типа (или формата): XXXXXXXX и -XXXX-XXXX.
  • Теперь я создаю GUID, используя эти 2 типа, чтобы собрать GUID с вызовом 4 частей следующим образом: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Чтобы различать эти два типа, я добавил параметр flag в функцию создания пары _p8(s), тот самый s параметр указывает функции, добавлять тире или нет.
  • В конце концов мы создаем GUID со следующей цепочкой: _p8() + _p8(true) + _p8(true) + _p8(), и верните его.

Ссылка на этот пост в моем блоге

Наслаждайтесь!:-)

Вот комбинация следующих факторов лучший ответ, за который проголосовали, с обходным путем для Столкновения 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);
        });
    };

В jsbin если вы хотите это протестировать.

Вот полностью несовместимая, но очень производительная реализация для генерации уникального идентификатора, подобного GUID, безопасного для ASCII.

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

Генерирует 26 символов [a-z0-9], получая UID, который одновременно короче и уникальнее, чем RFC-совместимые GUID.Тире можно тривиально добавить, если важна удобочитаемость для человека.

Вот примеры использования и тайминги для этой функции и несколько других ответов на этот вопрос.Синхронизация выполнялась под управлением Chrome m25, по 10 миллионов итераций каждая.

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

Вот код синхронизации.

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

Вот решение, датированное октябрем.9 декабря 2011 года из комментария пользователя джед в 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)}

Это достигает той же цели, что и текущий ответ с самым высоким рейтингом, но на 50 с лишним меньше байт за счет использования принуждения, рекурсии и экспоненциальной нотации.Для тех, кому интересно, как это работает, вот аннотированная форма более старой версии функции:

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

От технический блог саги шкеди:

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

Существуют и другие методы, которые предполагают использование элемента управления ActiveX, но держитесь от них подальше!

Редактировать : Я подумал, что стоит отметить, что ни один генератор GUID не может гарантировать уникальных ключей (проверьте статья в Википедии).Всегда есть вероятность столкновений.GUID просто предлагает достаточно большой набор ключей, чтобы свести изменение коллизий практически к нулю.

Вы можете использовать node-uuid (https://github.com/kelektiv/node-uuid)

Простая и быстрая генерация RFC4122 UUIDS.

Характеристики:

  • Сгенерировать UUID RFC4122 версии 1 или версии 4
  • Запускается в node.js и браузерах.
  • Криптографически надежная случайная генерация # на поддерживающих платформах.
  • Небольшая площадь (Хотите что-нибудь поменьше? Зацени это!)

Установка с помощью NPM:

npm install uuid

Или Используя uuid через браузер:

Загрузить Необработанный файл (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Загрузить необработанный файл (uuid v4): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js


Хотите еще меньше?Посмотри на это: https://gist.github.com/jed/982883


Использование:

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

Веб-сервис был бы полезен.

Быстрый поиск в Google: http://www.hoskinson.net/GuidGenerator/

Не могу поручиться за эту реализацию, но КТО-то должен опубликовать надежный генератор GUID.

С помощью такого веб-сервиса вы могли бы разработать веб-интерфейс REST, который использует веб-сервис GUID и обслуживает его через AJAX в javascript в браузере.

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

Редактировать:

Пересмотрел свой проект, в котором использовалась эта функция, и мне не понравилась многословность.- Но нужна была надлежащая случайность.

Версия, основанная на ответе Briguy37 и некоторых побитовых операторах для извлечения окон размером с кусочек из буфера.

Следует придерживаться схемы RFC типа 4 (random), поскольку в прошлый раз у меня были проблемы с разбором несоответствующих UUID с помощью UUID Java.

Простой модуль JavaScript как комбинация лучших ответов в этой теме.

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

Использование:

Guid.NewGuid()

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

Guid.пустой

"00000000-0000-0000-0000-000000000000"

От старая добрая википедия там есть ссылка на реализацию UUID на JavaScript.

Это выглядит довольно элегантно, и, возможно, могло бы быть улучшено путем добавления хэша IP-адреса клиента.Возможно, этот хэш можно было бы вставить в html-документ на стороне сервера для использования клиентским javascript.

Обновить :На оригинальном сайте произошла перетасовка, вот обновленная версия

Что ж, на этот вопрос уже есть куча ответов, но, к сожалению, в этой куче нет "истинного" рэндома.Приведенная ниже версия является адаптацией ответа бруфы, но обновлена, чтобы включить "истинную" случайную функцию, которая использует криптографические библиотеки там, где они доступны, и функцию Alea () в качестве запасного варианта.

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

Это создает UUID версии 4 (созданный из псевдослучайных чисел) :

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

Вот пример сгенерированных UUID :

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

JavaScript-проект на GitHub - https://github.com/LiosK/UUID.js

UUID.js Генератор UUID, совместимый с RFC, для JavaScript.

Смотрите RFC 4122 http://www.ietf.org/rfc/rfc4122.txt.

Функции Генерируют UUID, соответствующие RFC 4122.

Доступны UUID версии 4 (UUID из случайных чисел) и UUID версии 1 (UUID с привязкой ко времени).

Объект UUID предоставляет широкий доступ к UUID, включая доступ к полям UUID.

Низкое разрешение временных меток JavaScript компенсируется случайными числами .

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

Настроил мой собственный генератор UUID / GUID с некоторыми дополнительными функциями здесь.

Я использую следующие Кибо генератор случайных чисел должен быть немного более надежным с криптографической точки зрения.

Ниже приведен мой скрипт с исключенными методами Mash и Kybos из baagoe.com.

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

Лучший способ:

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
 }

Сведенный к минимуму:

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}

Я хотел понять ответ бруфы, поэтому расширил его и добавил комментарии:

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

Образец ES6

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

Это всего лишь простой вызов AJAX...

Если кому-то все еще интересно, вот мое решение.

На стороне сервера:

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

На стороне клиента:

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

Для тех, кому нужно решение, совместимое с rfc4122 версии 4, с учетом соображений скорости (несколько вызовов 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("");
}

Приведенная выше функция должна иметь приличный баланс между скоростью и случайностью.

Этот основан на дате и добавляет случайный суффикс, чтобы "обеспечить" уникальность.Хорошо работает с css-идентификаторами.Он всегда возвращает что-то вроде, и его легко взломать:

идентификационный номер пользователя-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;
        };

Я знаю, это старый вопрос.Просто для полноты картины, если вашей средой является SharePoint, существует служебная функция, вызываемая SP.Guid.newGuid (ссылка на msdn), который создает новый guid.Эта функция находится внутри файла sp.init.js.Если вы перепишете эту функцию (чтобы удалить некоторые другие зависимости из других частных функций), это будет выглядеть следующим образом:

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

Существует плагин jQuery, который прекрасно обрабатывает Guid @ http://plugins .jquery.com/project/GUID_Helper

jQuery.Guid.Value()

Возвращает значение внутреннего Guid.Если guid не был указан, возвращает новый (затем значение сохраняется внутри).


jQuery.Guid.New()

Возвращает новый Guid и устанавливает его значение внутри.


jQuery.Guid.Empty()

Возвращает пустой Guid 00000000-0000-0000-0000-0000-000000000000.


jQuery.Guid.IsEmpty()

Возвращает логическое значение.Значение True, если оно пустое / неопределенное / пустое /null.


jQuery.Guid.IsValid()

Возвращает логическое значение.True действительный guid, false, если нет.


jQuery.Guid.Set()

Возвращает Guid.Устанавливает Guid в значение Guid, указанное пользователем, если недопустимо, возвращает пустой guid.

Простой код, который использует crypto.getRandomValues(a) вкл . поддерживаемые браузеры (IE11+, iOS7 +, FF21 +, Chrome, Android Chrome).Избегает использования Math.random() потому что это может вызвать коллизии (например, 20 коллизий для 4000 сгенерированных uuid в реальной ситуации с помощью Мукса).

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

Примечания:

  • Оптимизирован для удобства чтения кода, а не для скорости, поэтому подходит, скажем, для нескольких сотен uuid в секунду.Генерирует около 10000 uuid () в секунду в Chromium на моем ноутбуке, используя http://jsbin.com/fuwigo/1 для измерения производительности.
  • Использует только 8 для "y", потому что это упрощает читаемость кода (y может быть 8, 9, A или B).
Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top