Создать GUID / UUID в JavaScript?

3498

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

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

  • 10
    Идентификаторы GUID, представленные в виде строк, имеют длину не менее 36 и не более 38 символов и соответствуют шаблону ^ \ {? [A-zA-Z0-9] {36}? \} $ И, следовательно, всегда являются ascii.
  • 1
    Дэвид Бау (David Bau) предоставляет гораздо лучший, удобочитаемый генератор случайных чисел на davidbau.com/archives/2010/01/30/… Я написал несколько иной подход к генерации UUID на blogs.cozi.com/tech/2010/04/generating- UUID , -в-javascript.html
Показать ещё 5 комментариев
Теги:
guid
uuid

55 ответов

2078
Лучший ответ

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

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

Некоторые примеры инструментов с открытым исходным кодом для работы с UUID, для некоторых популярных языков программирования перечислены здесь.

JavaScript

PHP

Идти

Рубин

питон


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

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

xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx

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

  • 169
    На самом деле RFC допускает UUID, которые создаются из случайных чисел. Вам просто нужно пару раз поиграть, чтобы идентифицировать его как таковой. Смотрите раздел 4.4. Алгоритмы создания UUID из действительно случайных или псевдослучайных чисел: rfc-archive.org/getrfc.php?rfc=4122
  • 1
    По сути, это решение, которое я использую - цель, для которой я его использую, достаточно проста и достаточна для моих нужд, хотя я мог видеть, что это вызывает проблемы у людей, у которых больше технических требований. Я предполагаю, что кто-то может поразить сервер для GUID, в зависимости от конкретной необходимости ...
Показать ещё 21 комментарий
3359

Для решения RFC4122 версии 4 это однострочное (ish) решение является самым компактным, с которым я мог бы справиться.

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() не гарантированно является высококачественным RNG. Подробнее см. Adam Hyland отличную запись на Math.random(). Для более надежного решения рассмотрите что-то вроде uuid module [Отказ от ответственности: я автор], который использует более качественные API-интерфейсы RNG, если таковые имеются.

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

Обновление, 2017-06-28: хорошая статья разработчиков Chrome, обсуждающая состояние Math.random Качество PRNG в Chrome, Firefox и Safari. tl; dr - По состоянию на конец 2015 года это "очень хорошо", но не криптографическое. Чтобы решить эту проблему, здесь приведена обновленная версия вышеупомянутого решения, которое использует ES6, API crypto и немного 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());
  • 65
    Безопасно ли использовать этот код для создания уникальных идентификаторов на клиенте, а затем использовать эти идентификаторы в качестве первичных ключей для сохранения объектов на сервере?
  • 30
    ... (продолжение) Шансы двух идентификаторов, генерируемых при столкновении этой функции, в буквальном смысле астрономически малы. Все, кроме 6 из 128 битов идентификатора, генерируются случайным образом, что означает, что для любых двух идентификаторов есть вероятность 1/2 ^^ 122 (или 5,3x10 ^^ 36), что они столкнутся.
Показать ещё 47 комментариев
684

Мне очень нравится, насколько чистый ответ Бройфа, но, к сожалению, плохие реализации 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);
    });
}


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

  • 27
    Имейте в виду, что new Date().getTime() не обновляется каждую миллисекунду. Я не уверен, как это влияет на ожидаемую случайность вашего алгоритма.
  • 44
    Я думаю, что это лучшие ответы просто потому, что он использует дату своего поколения. Однако, если у вас современный стек браузера, я рекомендую Date.now() для new Date().getTime()
Показать ещё 25 комментариев
332

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

Но если вы смотрите на что регулярное выражение, те много replace() обратные вызовы, toString() и 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

Для пояснения позвольте начать с кода брофы:

'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)).

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

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

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

  • 1
    jsperf.com позволит вам собирать данные и просматривать результаты в разных браузерах и на разных устройствах.
  • 0
    В e5 при объединении в 8 бит вы пропускаете 4 бит в части -4xxx- : вы только что получили ...,'-','4','x','-',... Или я что-то упустил? Помимо этого +1 для измерения производительности.
Показать ещё 14 комментариев
149

Здесь приведен код, основанный на 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;
}
  • 3
    Это не приводит к тире, необходимым для c #, чтобы проанализировать его в System.Guid. Это выглядит так: B42A153F1D9A4F92990392C11DD684D2, когда оно должно выглядеть так: B42A153F-1D9A-4F92-9903-92C11DD684D2
  • 5
    ABNF из спецификации содержит символы "-", поэтому я обновился, чтобы соответствовать требованиям.
Показать ещё 5 комментариев
82

Самый быстрый 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 ([email protected]).
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

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

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.6fb7687f префикс 0. (0.6fb7687f => 6fb7687f) и получаем строку длиной восемь шестнадцатеричных символов.
    (Math.random().toString(16).substr(2,8).
  • Иногда Math.random() возвращает более короткое число (например, 0.4363) из-за нулей в конце (из приведенного выше примера на самом деле это значение равно 0.4363000000000000). Вот почему я добавляю к этой строке "000000000" (строку с девятью нулями), а затем обрезаю ее с помощью функции substr() чтобы сделать ее точно равной девяти символам (заполняя нули справа).
  • Причина добавления ровно девяти нулей - в худшем случае, когда Math.random() будет возвращать ровно 0 или 1 (вероятность Math.random() ^ 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 частей, как -XXXX-XXXX ниже: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • Чтобы различать эти два типа, я добавил параметр flag в функцию _p8(s) пар _p8(s), s параметр s сообщает функции, добавлять ли тире или нет.
  • В конце концов мы создаем GUID со следующей цепочкой: _p8() + _p8(true) + _p8(true) + _p8() и возвращаем его.

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

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

  • 12
    Эта реализация неверна. Определенные символы GUID требуют особого отношения (например, 13-я цифра должна быть цифрой 4).
  • 1
    @JLRishe, вы правы, это не соответствует стандартам RFC4122. Но это все еще случайная строка, которая выглядит как GUID. Ура :-)
Показать ещё 1 комментарий
78
var uniqueId = Math.random().toString(36).substring(2) 
               + (new Date()).getTime().toString(36);

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

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

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

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

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

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

var r = (new Date()).getTime().toString(16) + Math.random().toString(16).substring(2) + "0".repeat(16);
var guid = r.substr(0,8) + '-' + r.substr(8,4) + '-4000-8' + r.substr(12,3) + '-' + r.substr(15,12);
document.getElementById("unique").innerHTML = guid;
<div id="unique">
</div>

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

  • 1
    Это не UUID, хотя?
  • 0
    UUID / GUID - это номер 122 бит (+ шесть зарезервированных битов). он может гарантировать уникальность через глобальную счетную службу, но часто он ретранслирует время, MAC-адрес и случайность. UUID не случайны! Предлагаемый здесь UID не полностью сжат. Вы можете сжать его до 122-битного целого числа, добавить 6 предопределенных битов и дополнительные случайные биты (удалить несколько битов таймера), и в итоге вы получите идеально сформированный UUID / GUID, который вам затем придется преобразовать в шестнадцатеричное. Для меня это не добавляет ничего, кроме соответствия длине удостоверения личности.
Показать ещё 1 комментарий
57

Вот комбинация верхнего голосуемого ответа с обходным решением для столкновений Chrome:

generateGUID = (typeof(window.crypto) != 'undefined' && 
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // /questions/1755/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, если вы хотите проверить его.

  • 2
    Я считаю, что в IE это на самом деле window.msCrypto вместо window.crypto. Может быть, неплохо проверить оба. См. Msdn.microsoft.com/en-us/library/ie/dn265046(v=vs.85).aspx
  • 3
    обратите внимание, что первая версия, window.crypto.getRandomValues , 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 .
56

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

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

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

Вот примеры использования и тайминги для этой функции, а некоторые из них - другие ответы. Сроки выполнялись в 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');
53

Здесь решение от 9 октября 2011 г. из комментария пользователя jed на 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
      )
}
  • 1
    В TypeScript используйте это: export const UUID = function b (a: number): string { return a ? (a^Math.random()*16>>a/4).toString(16) : (''+[1e7]+-1e3+-4e3+-8e3+-1e11).replace(/[018]/g, b) };
32

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

Простое, быстрое поколение RFC4122 UUIDS.

Особенности:

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

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

npm install uuid

Или используя 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


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

// 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();
  • 0
    Сырой Файл мертв.
  • 1
    @Edward Olamisan Обновлен новый источник для замены устаревшей версии.
Показать ещё 3 комментария
31

Из технического журнала 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;
}

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

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

  • 7
    Обратите внимание, что это не GUID в техническом смысле, потому что он не делает ничего, чтобы гарантировать уникальность. Это может иметь или не иметь значения в зависимости от вашего приложения.
  • 0
    То же самое и к ответу Стивена. Если вам нужна уникальность, определите ее на стороне сервера, где мы надеемся получить правильный алгоритм!
Показать ещё 3 комментария
29

Полезен веб-сервис.

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

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

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

  • 10
    Я сделал, хост и использовать этот: timjeanes.com/guid . Он использует .NET для генерации нового GUID и возвращает его без каких-либо дополнительных ошибок. Это также будет работать над JSONP.
  • 8
    Веб-сервис для обслуживания GUID, правда? Это почти так же странно, как написание веб-службы для обслуживания случайных чисел - если только вам не нужны действительно действительно случайные числа, производимые каким-либо физическим источником шума, подключенным к серверу, то есть.
Показать ещё 2 комментария
28

Простой модуль 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.empty

     

"00000000-0000-0000-0000-000000000000"

  • 1
    Что беспокоит всех ответов, так это то, что для JavaScript нормально хранить GUID в виде string . Ваш ответ, по крайней мере, касается гораздо более эффективного хранилища с использованием Uint16Array . Функция toString должна использовать двоичное представление в object JavaScript
  • 2
    _cryptoGuid не _cryptoGuid включать '4' в начале 3-го раздела, как _guid ?
Показать ещё 4 комментария
28
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);
    });
};

EDIT:

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

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

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

  • 0
    На jsbin: jsbin.com/uqives/2 Стоит более четко указать , что это не работает в IE. Не работал для Firefox также в моем тесте.
  • 0
    Спасибо за попытку. Я взбил его для расширения Chrome. Я не проверял факты, которые я прочитал в Internt (tm) о Firefox, поддерживающих его. Также стоит отметить, что это не соответствует RFC, случайный (Версия 4) UUID должен иметь два места с фиксированными значениями: en.wikipedia.org/wiki/…
24

Из good ol 'wikipedia есть ссылка на реализацию UUID javascript.

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

ОБНОВЛЕНИЕ: Исходный сайт имел перетасовку, вот обновленная версия

  • 2
    Ссылка мертва. Можете ли вы предоставить альтернативу?
  • 1
    Эта реализация хороша, потому что в отличие от ответов выше она также включает временную метку, которая должна улучшить уникальность в браузерах с некачественным генератором случайных чисел.
22

Ну, у этого уже есть куча ответов, но, к сожалению, в связке нет "истинного" случайного. Нижеприведенная версия является адаптацией ответа broofa, но обновлена, чтобы включить "истинную" случайную функцию, которая использует доступные криптографические библиотеки, и функцию 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 <[email protected]>, 2010
      function Mash() {
          var n = 0xefc8249d;

          var mash = function(data) {
              data = data.toString();
              for (var i = 0; i < data.length; i++) {
                  n += data.charCodeAt(i);
                  var h = 0.02519603282416938 * n;
                  n = h >>> 0;
                  h -= n;
                  h *= n;
                  n = h >>> 0;
                  h -= n;
                  n += h * 0x100000000; // 2^32
              }
              return (n >>> 0) * 2.3283064365386963e-10; // 2^-32
          };

          mash.version = 'Mash 0.9';
          return mash;
      }

      // From http://baagoe.com/en/RandomMusings/javascript/
      function Alea() {
          return (function(args) {
              // Johannes Baagøe <[email protected]>, 2010
              var s0 = 0;
              var s1 = 0;
              var s2 = 0;
              var c = 1;

              if (args.length == 0) {
                  args = [+new Date()];
              }
              var mash = Mash();
              s0 = mash(' ');
              s1 = mash(' ');
              s2 = mash(' ');

              for (var i = 0; i < args.length; i++) {
                  s0 -= mash(args[i]);
                  if (s0 < 0) {
                      s0 += 1;
                  }
                  s1 -= mash(args[i]);
                  if (s1 < 0) {
                      s1 += 1;
                  }
                  s2 -= mash(args[i]);
                  if (s2 < 0) {
                      s2 += 1;
                  }
              }
              mash = null;

              var random = function() {
                  var t = 2091639 * s0 + c * 2.3283064365386963e-10; // 2^-32
                  s0 = s1;
                  s1 = s2;
                  return s2 = t - (c = t | 0);
              };
              random.uint32 = function() {
                  return random() * 0x100000000; // 2^32
              };
              random.fract53 = function() {
                  return random() +
                      (random() * 0x200000 | 0) * 1.1102230246251565e-16; // 2^-53
              };
              random.version = 'Alea 0.9';
              random.args = args;
              return random;

          }(Array.prototype.slice.call(arguments)));
      };
      return Alea();
  }
}());

Math.guid = function() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c)    {
      var r = Math.trueRandom() * 16 | 0,
          v = c == 'x' ? r : (r & 0x3 | 0x8);
      return v.toString(16);
  });
};
  • 2
    Вам необходимо закомментировать строку rval = rval & mask так как она rval = rval & mask результат до 32 бит. Операции с битами - только 32 бита в JS. Более того, если вы применяете его только в конце, тогда 3 младших бита уже потеряны при генерировании 53-битного значения, поскольку первый цикл создает 56-битное значение (255 * 2 ^ 48). Вместо этого вам нужно использовать этот код: `var byte = byteArray [i]; if (p + 8> bits_needed) byte & = (255 >> p + 8 - bits_needed); rval + = byte * Math.pow (2, p); `Вы можете посмотреть тест здесь: jsfiddle.net/xto6969y/1
  • 3
    Также вы можете рассмотреть возможность использования var crypto = window.crypto || window.msCrypto см. msdn.microsoft.com/library/dn265046(v=vs.85).aspx
Показать ещё 4 комментария
22

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

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

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

Возможности Создает совместимые с RFC 4122 UUID.

Версии 4 UUID (UUID от случайных чисел) и UUID версии 1 (временные UUID).

Объект UUID допускает разнообразный доступ к UUID, включая доступ к поля UUID.

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

20

Это создаст 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
16
  // 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('-');
  • 1
    Мне нравится такой подход, но учтите, что он не работает должным образом в Chrome. Часть ".slice (2, 14)" возвращает только 8 символов, а не 12.
13

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

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

Ниже приведен мой script с помощью методов 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 <[email protected]>, 2010
  //function Mash() {...};

  // From http://baagoe.com/en/RandomMusings/javascript/
  //function Kybos() {...};

  var rnd = Kybos();

  //UUID/GUID Implementation from http://frugalcoder.us/post/2012/01/13/javascript-guid-uuid-generator.aspx
  var UUID = {
    "empty": "00000000-0000-0000-0000-000000000000"
    ,"parse": function(input) {
      var ret = input.toString().trim().toLowerCase().replace(/^[\s\r\n]+|[\{\}]|[\s\r\n]+$/g, "");
      if ((/[a-f0-9]{8}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{4}\-[a-f0-9]{12}/).test(ret))
        return ret;
      else
        throw new Error("Unable to parse UUID");
    }
    ,"createSequential": function() {
      var ret = new Date().valueOf().toString(16).replace("-","")
      for (;ret.length < 12; ret = "0" + ret);
      ret = ret.substr(ret.length-12,12); //only least significant part
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"create": function() {
      var ret = "";
      for (;ret.length < 32;ret += Math.floor(rnd() * 0xffffffff).toString(16));
      return [ret.substr(0,8), ret.substr(8,4), "4" + ret.substr(12,3), "89AB"[Math.floor(Math.random()*4)] + ret.substr(16,3),  ret.substr(20,12)].join("-");
    }
    ,"random": function() {
      return rnd();
    }
    ,"tryParse": function(input) {
      try {
        return UUID.parse(input);
      } catch(ex) {
        return UUID.empty;
      }
    }
  };
  UUID["new"] = UUID.create;

  w.UUID = w.Guid = UUID;
}(window || this));
12

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

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

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

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

Для тех, кто хочет получить совместимое с 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("");
}

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

11

Это просто простой вызов 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.");
    }
);
  • 0
    Ваш метод является единственно правильным, но проблема в том, что он асинхронный, поэтому вы не можете его использовать. Кроме того, попробуйте проделать это несколько раз от 100 до 1000 раз, и вы столкнетесь с IE (но не с Chrome и Firefox). Нам нужны синхронные вызовы: используйте JQuery, а не MS-PageMethod JavaScript!
  • 2
    Вы правы, вызывается асинхронно, это не очень полезно. По иронии судьбы мой оригинальный код использует jQuery для синхронного вызова этого метода. Вот пример: $ .ajax ({async: false, тип: 'POST', url: 'MyPage.aspx / GenerateGuid', contentType: 'application / json; charset = utf-8', data: '{}', success: function (data) {// данные содержат ваш новый GUID}, fail: function (msg) {alert (msg);}});
Показать ещё 2 комментария
10

Пример ES6

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

Я знаю, это старый вопрос. Для полноты, если ваша среда - SharePoint, есть функция утилиты, называемая SP.Guid.newGuid (msdn link), которая создает новый 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;
};
10

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

jQuery.Guid.Value()

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


jQuery.Guid.New()

Возвращает новое руководство и устанавливает его значение внутри.


jQuery.Guid.Empty()

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


jQuery.Guid.IsEmpty()

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


jQuery.Guid.IsValid()

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


jQuery.Guid.Set()

Регламент. Устанавливает Guid для указанного пользователем Guid, если недействительно, возвращает пустой указатель.

  • 1
    Ссылка на плагин не работает
9

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

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

Странно, что никто еще не упомянул об этом, но для полноты, существует множество генераторов guid на npm. Я готов поспорить, что большинство из них работают в браузере тоже.

6

Если вам просто нужна случайная 128-битная строка в каком-либо конкретном формате, вы можете использовать:

function uuid() {
    return crypto.getRandomValues(new Uint32Array(4)).join('-');
}

Что вернет что-то вроде 2350143528-4164020887-938913176-2513998651.

  • 0
    Не поддерживается для версий IE ниже 11 - caniuse
  • 0
    Кстати, почему он генерирует только цифры, а не символы? гораздо менее безопасный
Показать ещё 4 комментария
5

Еще один более читаемый вариант с двумя мутациями.

function uuid4()
{
  function hex (s, b)
  {
    return s +
      (b >>> 4   ).toString (16) +  // high nibble
      (b & 0b1111).toString (16);   // low nibble
  }

  let r = crypto.getRandomValues (new Uint8Array (16));

  r[6] = r[6] >>> 4 | 0b01000000; // Set type 4: 0100
  r[8] = r[8] >>> 3 | 0b10000000; // Set variant: 100

  return r.slice ( 0,  4).reduce (hex, '' ) +
    r.slice ( 4,  6).reduce (hex, '-') +
    r.slice ( 6,  8).reduce (hex, '-') +
    r.slice ( 8, 10).reduce (hex, '-') +
    r.slice (10, 16).reduce (hex, '-');
}
  • 0
    Это не работает из-за прекрасного ASI JavaScripts (протестировано в Chrome 66 на MacOS 10.13.3). Изменить : это должно быть исправлено сейчас.
  • 0
    Ну, большинство разработчиков js - веб-разработчики, и мы не поймем, что делают побитовые операторы, потому что мы не используем их большую часть времени, когда мы разрабатываем. На самом деле я никогда не нуждался ни в одном из них, и с 1997 года являюсь разработчиком JS. Таким образом, ваш пример кода по-прежнему совершенно не читается обычным веб-разработчиком, который его прочтет. Не говоря уже о том, что вы по-прежнему используете однобуквенные имена переменных, что делает его еще более загадочным. Возможно, прочитайте Чистый код, может быть, это поможет: amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/…
5

Важно, чтобы использовать хорошо протестированный код, который поддерживается более чем одним участником, вместо того, чтобы бить ваши собственные вещи для этого. Это одно из мест, где вы, вероятно, предпочитаете наиболее стабильный код, чем кратчайшая возможная умная версия, работающая в X-браузере, но не учитывающая особенности Y, которые часто приводят к очень сложному исследованию ошибок, чем проявляются только случайным образом для некоторых пользователей. Лично я использую uuid-js в https://github.com/aurigadl/uuid-js, с помощью которого активирована поддержка, чтобы я мог легко получать обновления.

  • 0
    Генерация идентификатора - такая простая и простая вещь в программе. Включение фреймворков, библиотек и того, что нет, для каждой маленькой задачи делает раздутый и медленный код. В конце концов, вкладчик в изменение климата .... :)
4

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

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).
  • 1
    jsfiddle.net/of3v5zko Jsfiddle, который использует криптографический API для генерации UUID, в соответствии с RFC4122 версии 4 Первоначальный источник github.com/Chalarangelo/30-seconds-of-code#uuid-generator
  • 0
    @ananda Спасибо. Однако этот код не имеет обратной совместимости с существующими браузерами. Кроме того, хотя этот код сохраняет несколько байтов, я думаю, что он менее читабелен (мне нравится мой код, чтобы быть ясным), и вполне возможно, что после uglifier и gzipping ваша версия ничего не сохраняет (серия символов x и общие идентификаторы сжимаются очень хорошо) , - Робокат 8 минут назад
3

Вы можете использовать некоторые пакеты npm (прямо, если node.js, прокрутите страницу, если на стороне интерфейса)

uuid

node-uuid

3

Я нашел этот script полезным для создания GUID в JavaScript

https://github.com/addui/GUIDJS

var myGuid = GUID();
3

На всякий случай, если кто-либо заходит по Google, ищет небольшую библиотеку-утилиту, ShortId (https://www.npmjs.com/package/shortid) отвечает всем требованиям этого вопроса. Он позволяет указать допустимые символы и длину и гарантирует последовательность, не повторяющуюся, не повторяющуюся.

Чтобы сделать это более реальным ответом, ядро ​​этой библиотеки использует следующую логику для создания своих коротких идентификаторов:

function encode(lookup, number) {
    var loopCounter = 0;
    var done;

    var str = '';

    while (!done) {
        str = str + lookup( ( (number >> (4 * loopCounter)) & 0x0f ) | randomByte() );
        done = number < (Math.pow(16, loopCounter + 1 ) );
        loopCounter++;
    }
    return str;
}

/** Generates the short id */
function generate() {

    var str = '';

    var seconds = Math.floor((Date.now() - REDUCE_TIME) * 0.001);

    if (seconds === previousSeconds) {
        counter++;
    } else {
        counter = 0;
        previousSeconds = seconds;
    }

    str = str + encode(alphabet.lookup, version);
    str = str + encode(alphabet.lookup, clusterWorkerId);
    if (counter > 0) {
        str = str + encode(alphabet.lookup, counter);
    }
    str = str + encode(alphabet.lookup, seconds);

    return str;
}

Я не редактировал это, чтобы отражать только самые основные части этого подхода, поэтому приведенный выше код содержит некоторую дополнительную логику из библиотеки. Если вам интересно все, что он делает, посмотрите на источник: https://github.com/dylang/shortid/tree/master/lib

3

Вы можете использовать npm package guid, генератор направляющих и валидатор.

https://www.npmjs.com/package/guid

Пример:

Guid.raw();
// -> '6fdf6ffc-ed77-94fa-407e-a7b86ed9e59d'

UPDATE: этот пакет устарел. Вместо этого используйте uuid.

https://www.npmjs.com/package/uuid

Пример:

const uuidv4 = require('uuid/v4');
uuidv4(); // ⇨ '10ba038e-48da-487b-96e8-8d3b99b6d18a'
  • 1
    Это, кажется, не поддерживается.
  • 1
    Спасибо, что сообщили мне @ inf3rno, я обновил свой ответ альтернативой
3

Я использую эту функцию ниже, надеюсь, что это может быть полезно.

    function NewGuid()
         {
           var sGuid="";
           for (var i=0; i<32; i++)
            {
              sGuid+=Math.floor(Math.random()*0xF).toString(0xF);
            }
           return sGuid;
         }
  • 2
    Есть ли причина использовать 0xF вместо 15 ?
2

Привет, вот рабочий пример, он генерирует 32-значный уникальный UUID.

function generateUUID() {
      var d = new Date();
      var k = d.getTime();
     var str = k.toString(16).slice(1)
    var UUID= 'xxxx-xxxx-4xxx-yxxx-xzx'.replace(/[xy]/g, function (c)
      {
        var r = Math.random() * 16 | 0;
        v = c == 'x' ? r : (r & 3 | 8);
        return v.toString(16);
      });
      var newString = UUID.replace(/[z]/, str)
      return newString;
    }
    var x = generateUUID()
    console.log(x,x.length)
2

Для моего случая использования мне потребовалось создание поколения, которое гарантировалось бы уникальным в глобальном масштабе; без исключений. Некоторое время я боролся с проблемой и придумал решение под названием tuid (Truly Unique ID). Он генерирует идентификатор с первыми 32 символами, сгенерированными системой, и оставшиеся цифры, представляющие миллисекунды с эпохи. В ситуациях, когда мне нужно генерировать id на клиентском javascript, он работает хорошо. Посмотрите:

https://github.com/mongoh/tuid

  • 0
    Это буквально вызывает AWS S3 для получения случайного идентификатора. Если вызов сервера в порядке, вы можете просто сгенерировать UUID.
1

основанный на работе broofa, я добавил еще несколько случайностей, добавив метку времени в math.random()

Надеюсь, это может помочь

function uuidv4() {
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
        var r = parseFloat('0.' + Math.random().toString().replace('0.', '') + new Date().getTime()) * 16 | 0,
            v = c == 'x' ? r : (r & 0x3 | 0x8);
        return v.toString(16);
    });
}
1

Для тех, кто использует Javascript в Windows (например, WScript/CScript/MSHTA). Можно использовать ActiveX. В частности, объект Scriptlet.Typelib:

WScript.Echo((new ActiveXObject("Scriptlet.TypeLib")).Guid)

Обратите внимание, что этот ответ работает только на тех технологиях, которые я перечисл, он не будет работать ни в одном браузере, даже в Microsoft Edge! Таким образом, ваш пробег будет отличаться от этого ответа.

  • 4
    Такой подход все еще вещь в 2018 году? Вот это да :-)
1

Здесь вы можете найти очень маленькую функцию, которая генерирует uuids https://gist.github.com/jed/982883

Одна из окончательных версий:

function b(
  a                  // placeholder
){
  var cryptoObj = window.crypto || window.msCrypto; // for IE 11
  return a           // if the placeholder was passed, return
    ? (              // a random number from 0 to 15
      a ^            // unless b is 8,
      cryptoObj.getRandomValues(new Uint8Array(1))[0]  // 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
      )
}
0

ОК, используя пакет uuid, он поддерживает UUID версий 1, 3, 4 и 5:

yarn add uuid

а потом:

const uuidv1 = require('uuid/v1');
uuidv1(); // ⇨ '45745c60-7b1a-11e8-9c9c-2d42b21b1a3e'

Вы также можете сделать это с помощью полностью определенных опций:

const v1options = {
  node: [0x01, 0x23, 0x45, 0x67, 0x89, 0xab],
  clockseq: 0x1234,
  msecs: new Date('2011-11-01').getTime(),
  nsecs: 5678
};
uuidv1(v1options); // ⇨ '710b962e-041c-11e1-9234-0123456789ab'

Для получения дополнительной информации посетите страницу npm здесь

0

Я не смог найти ответа, который бы использовал один 16- TypedArray и DataView, поэтому я думаю, что следующее решение для генерации UUID версии 4 для RFC будет стоять здесь самостоятельно:

function uuid4() {
    const ho = (n, p) => n.toString(16).padStart(p, 0); /// Return the hexadecimal text representation of number 'n', padded with zeroes to be of length 'p'
    const view = new DataView(new ArrayBuffer(16)); /// Create a view backed by a 16-byte buffer
    crypto.getRandomValues(new Uint8Array(view.buffer)); /// Fill the buffer with random data
    view.setUint8(6, (view.getUint8(6) & 0xf) | 0x40); /// Patch the 6th byte to reflect a version 4 UUID
    view.setUint8(8, (view.getUint8(8) & 0x3f) | 0x80); /// Patch the 8th byte to reflect a variant 1 UUID (version 4 UUIDs are)
    return '${ho(view.getUint32(0), 8)}-${ho(view.getUint16(4), 4)}-${ho(view.getUint16(6), 4)}-${ho(view.getUint16(8), 4)}-${ho(view.getUint32(10), 8)}${ho(view.getUint16(14), 4)}'; /// Compile the canonical textual form from the array data
}

Я предпочитаю это, потому что он опирается только на функции, доступные для стандартной платформы ECMAScript.

0

Для науки. Я еще не видел, чтобы кто-то это делал... это не совместимо с v4, но его можно было легко изменить. Это просто пример расширения типа Uint8Array и использование crypto.getRandomValues() для генерации значений байтов uuid.

class uuid extends Uint8Array {
        constructor() {
            super(16)
            /* not v4, just some random bytes */
            window.crypto.getRandomValues(this)
        }
        toString() {
            let id = new String()
            for (let i = 0; i < this.length; i++) {
                /*convert uint8 to hex string */
                let hex = this[i].toString(16).toUpperCase()

                /*add zero padding*/
                while (hex.length < 2) {
                    hex = String(0).concat(hex)
                }
                id += hex

                /* add dashes */
                if (i == 4 || i == 6 || i == 8 || i == 10 || i == 16){
                    id += '-'
                }
            }
            return id
        }
    }
0
function randomHex(length) {
    var random_string = '';
    if(!length){
        length = 1;
    }
    for(var i=0; i<length; i+=1){
        random_string += Math.floor(Math.random() * 15).toString(16);
    }
    return random_string;
}

function guid() {
    return randomHex(8);
}
0

Это может быть полезно кому-то...

var d = new Date().valueOf();
var n = d.toString();
var result = '';
var length = 32;
var p = 0;
var chars = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';

for (var i = length; i > 0; --i){
    result += ((i & 1) && n.charAt(p) ? '<b>' + n.charAt(p) + '</b>' : chars[Math.floor(Math.random() * chars.length)]);
    if(i & 1) p++;
};

https://jsfiddle.net/j0evrdf1/1/

0

Просто подумал, что я отправлю еще один способ сделать то же самое.

function guid() {
  var chars = ["0","1","2","3","4","5","6","7","8","9","A","B","C","D","E","F"];
  var str = "";
  for(var i=0;i<36;i++) {
    var str = str + ((i == 8 || i == 13 || i == 18 || i == 23) ? "-" : chars[Math.floor(Math.random()*chars.length)]);
  };
  return str;
}
0

Простое решение для генерации уникальной идентификации - использовать токен времени и добавить к нему случайное число. Я предпочитаю префикс "uuid-".

Ниже функция генерирует случайную строку типа: uuid-14d93eb1b9b4533e6. Не нужно генерировать 32 символа случайной строки. 16 char случайная строка более чем достаточна в этом случае, чтобы предоставить уникальные UUID в javascript.

var createUUID = function() {
  return"uuid-"+((new Date).getTime().toString(16)+Math.floor(1E7*Math.random()).toString(16));
}
-1

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

Используя Change.js, вы получаете уникальный GUID с одной строкой кода:

var chance = new Chance();

document.body.innerHTML = chance.guid();
body { font-family: Tahoma }
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Chance.js</title>
</head>
<body>
<script src="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.js"></script>
<link href="//cdn.jsdelivr.net/chartist.js/latest/chartist.min.css" rel="stylesheet" type="text/css" />
  <script src="http://chancejs.com/chance.min.js"></script>
</body>
</html>
  • 3
    Добавление библиотеки для одной функции просто неприлично.
-1

Тот, который я использовал в последнее время:

const uuid = function b(a) {
  return a ? (a ^ Math.random() * 16 >> a / 4).toString(16) :
      ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, b);
};
-8

у него есть зависимость от mongodb, конечно, но у меня лично это где-то вокруг в любом случае, поэтому генерация нового идентификатора проста:

const ObjectID = require('mongodb').ObjectID;
let id = new ObjectID().toString();
-12

Я знаю, что эта тема старая, но если вы действительно хотели создать GUID, вы могли бы obvioulsy сделать это без прямого javascript. Вы можете привести к истечению срока действия каждой загрузки и создать GUID на стороне сервера, а затем заполнить ее в переменной javascript во время выполнения страницы. Просто идея.

  • 0
    Несколько сурово судить. Это простое решение довольно сложной проблемы. Если честно, я, вероятно, собираюсь использовать решение, подобное этому. Вопрос со всем javascript заключается в том, какой манейный Guid вам нужно генерировать? Если вам действительно нужны сотни, то сделайте это, но для большинства задач требуется всего одна или две, так почему бы не сгенерировать их заранее при загрузке страницы на сервере?
  • 8
    @ Adam просто потому, что некоторые приложения работают только на стороне клиента без поддержки сценариев на стороне сервера, и потому что OP попросил об этом. Второе предположение, что кто-то ничего не решает. Лично я использую ajax-вызов в приложении для получения новых идентификаторов GUID, но мое требование отличается от OP.

Ещё вопросы

Сообщество Overcoder
Наверх
Меню