Создать GUID/UUID в JavaScript?
Я пытаюсь создать глобально уникальные идентификаторы в JavaScript. Я не уверен, какие подпрограммы доступны во всех браузерах, как "случайные" и засеянные встроенным генератором случайных чисел, и т.д.
Идентификатор GUID/UUID должен быть не менее 32 символов и должен оставаться в диапазоне ASCII, чтобы избежать проблем при их передаче.
Ответы
Ответ 1
UUID (универсальный уникальный идентификатор), также известный как GUID (глобальный уникальный идентификатор), согласно RFC 4122, являются идентификаторами с определенной гарантией уникальности.
Лучший способ создать их - следовать инструкциям по реализации в упомянутом RFC, использовать одну из многих проверенных реализаций с открытым исходным кодом.
Популярный инструмент с открытым исходным кодом для работы с UUID в JavaScript - это node-uuid
Обратите внимание, что просто случайная генерация идентификаторов побайтово или посимвольно не даст вам таких же гарантий, как соответствующая реализация. Кроме того, очень важно, что системы, работающие с совместимыми UUID, могут не принимать случайно сгенерированные, и многие валидаторы с открытым исходным кодом фактически проверяют правильность структуры.
UUID должен иметь этот формат:
xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx
Где позиции M и N могут иметь только определенные значения. В настоящее время единственными допустимыми значениями для M являются 1, 2, 3, 4 и 5, поэтому случайная генерация этой позиции сделает большинство результатов неприемлемыми.
Ответ 2
Для 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());
Ответ 3
Мне очень нравится, как чистый ответ Broa, но, к сожалению, плохие реализации Math.random
оставляют возможность столкновения.
Здесь аналогичное RFC4122 совместимое с версией 4 решение, которое решает эту проблему путем смещения первых 13 шестнадцатеричных чисел на шестнадцатеричную часть временной метки и однократного смещения на шестнадцатеричную часть микросекунд с момента загрузки страницы. Таким образом, даже если Math.random
находится на одном и том же начальном этапе, оба клиента должны будут генерировать UUID с одинаковым количеством микросекунд с момента загрузки страницы (если поддерживается время высокой производительности) И в ту же миллисекунду (или 10, 000+ лет спустя), чтобы получить тот же UUID:
function generateUUID() { // Public Domain/MIT
var d = new Date().getTime();//Timestamp
var d2 = (performance && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported
return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
var r = Math.random() * 16;//random number between 0 and 16
if(d > 0){//Use timestamp until depleted
r = (d + r)%16 | 0;
d = Math.floor(d/16);
} else {//Use microseconds since page-load if supported
r = (d2 + r)%16 | 0;
d2 = Math.floor(d2/16);
}
return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
});
}
console.log(generateUUID())
Ответ 4
Ответ на броуф довольно гладкий, действительно - впечатляюще умный, действительно... 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.
Ответ 5
Здесь приведен код, основанный на 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;
}
Ответ 6
let uniqueId = Math.random().toString(36).substring(2) + Date.now().toString(36);
document.getElementById("unique").innerHTML =
Math.random().toString(36).substring(2) + (new Date()).getTime().toString(36);
<div id="unique">
</div>
Ответ 7
Самый быстрый 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()
и возвращаем его.
Ссылка на этот пост в моем блоге
Наслаждайтесь! :-)
Ответ 8
Вот комбинация верхнего голосуемого ответа с обходным решением для столкновений 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, если вы хотите проверить его.
Ответ 9
Вот полностью несовместимая, но очень эффективная реализация для создания уникального идентификатора с идентификатором 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');
Ответ 10
Здесь решение от 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
)
}
Ответ 11
Из саги шкеды технического блога:
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 просто предлагает достаточно большой набор ключей, чтобы уменьшить количество столкновений почти до нуля.
Ответ 12
Вы можете использовать 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();
Ответ 13
Полезен веб-сервис.
Быстрый поиск Google: http://www.hoskinson.net/GuidGenerator/
Нельзя ручаться за эту реализацию, но кто-то должен опубликовать генератор GUID bonafide.
С таким веб-сервисом вы можете разработать веб-интерфейс REST, который использует веб-службу GUID, и служит через AJAX для javascript в браузере.
Ответ 14
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.
Ответ 15
Простой модуль 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());
Ответ 16
Из good ol 'wikipedia есть ссылка на реализацию UUID javascript.
Он выглядит довольно элегантно и, возможно, может быть улучшен путем соления с хешем IP-адреса клиента. Этот хэш, возможно, может быть вставлен в сервер html-документа для использования на стороне клиента javascript.
ОБНОВЛЕНИЕ: Исходный сайт имел перетасовку, вот обновленная версия
Ответ 17
Что ж, у этого уже есть куча ответов, но, к сожалению, в этой группе нет "истинного" случайного числа. Приведенная ниже версия является адаптацией ответа 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 https://web.archive.org/web/20120502223108/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);
});
};
Ответ 18
Проект 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 компенсируется случайным числа.
Ответ 19
Это создаст 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
Ответ 20
// 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('-');
Ответ 21
Настроил мой собственный генератор 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));
Ответ 22
Я хотел понять ответ 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);
}
);
};
Ответ 23
Это просто простой вызов 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.");
}
);
Ответ 24
Лучший способ:
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}
Ответ 25
Пример ES6
const guid=()=> {
const s4=()=> Math.floor((1 + Math.random()) * 0x10000).toString(16).substring(1);
return `${s4() + s4()}-${s4()}-${s4()}-${s4()}-${s4() + s4() + s4()}`;
}
Ответ 26
Для тех, кто хочет rfc4122 версии 4 совместимого решения с соображениями скорости (несколько обращений к Math.random()):
var rand = Math.random;
function UUID() {
var nbr, randStr = "";
do {
randStr += (nbr = rand()).toString(16).substr(3, 6);
} 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)
);
}
console.log( UUID() );
Ответ 27
Это основано на дате и добавляет случайный суффикс для "обеспечения" уникальности.
Хорошо работает для идентификаторов 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;
};
Ответ 28
Существует плагин 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, если недействительно, возвращает пустой указатель.
Ответ 29
Я знаю, это старый вопрос. Для полноты, если ваша среда - 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;
};
Ответ 30
Простой код, который использует 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);
}
Заметки:
- Оптимизирован для удобочитаемости кода, а не скорости, поэтому подходит, например, для нескольких сотен единиц в секунду. Генерирует около 10000 uuid() в секунду в Chromium на моем ноутбуке, используя http://jsbin.com/fuwigo/1 для измерения производительности.
- Использует только 8 для "y", потому что это упрощает читабельность кода (y может быть 8, 9, A или B).