如何创建GUID / UUID?

5319

如何在JavaScript中创建GUID(全局唯一标识符)?GUID / UUID应至少为32个字符,并应保持在ASCII范围内,以避免在传递时出现问题。

我不确定所有浏览器都可用哪些例程,内置的随机数生成器有多“随机”和有多少种子等信息。


38
GUIDs表示为字符串时,长度至少为36个字符,最多不超过38个字符,并匹配模式^{?[a-zA-Z0-9]{36}?}$,因此始终为ASCII码。 - AnthonyWJones
5
David Bau在http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html提供了一个更好的、可初始化的随机数生成器。我在http://blogs.cozi.com/tech/2010/04/generating-uuids-in-javascript.html中记录了一种略微不同的生成UUID的方法。 - George V. Reilly
1
很奇怪还没有人提到这一点,但为了完整起见,在npm上有大量的guid生成器。我敢打赌它们中的大多数也可以在浏览器中使用。 - George Mauer
2
12年后,使用BigInt和ES6类以及其他技术,可以实现每秒500,000个uuid的速率。参见参考链接 - smallscript
5
如其他人所提到的,如果您只在浏览器中生成少量uuid,则只需使用URL.createObjectURL(new Blob()).substr(-36)即可。该方法得到了很好的浏览器支持。为避免内存泄漏,需要调用 URL.revokeObjectURL(url) - rinogo
显示剩余2条评论
73个回答

5

如果您将 let buffer = new Uint8Array(); crypto.getRandomValues 替换为 let buffer = crypto.randomBytes(16),这也适用于Node.js。

在性能上,它应该能够击败大多数正则表达式的解决方案。

const hex = '0123456789ABCDEF'

let generateToken = function() {
    let buffer = new Uint8Array(16)

    crypto.getRandomValues(buffer)

    buffer[6] = 0x40 | (buffer[6] & 0xF)
    buffer[8] = 0x80 | (buffer[8] & 0xF)

    let segments = []

    for (let i = 0; i < 16; ++i) {
        segments.push(hex[(buffer[i] >> 4 & 0xF)])
        segments.push(hex[(buffer[i] >> 0 & 0xF)])

        if (i == 3 || i == 5 || i == 7 || i == 9) {
            segments.push('-')
        }
    }

    return segments.join('')
}

for (let i = 0; i < 100; ++i) {
  console.log(generateToken())
}

性能图表(大家都喜欢它们):jsbench


5

这是什么样子

let uuid = function(){
     return Array
      .from(Array(16))
      .map(e => Math.floor(Math.random() * 255)
      .toString(16)
      .padStart(2,"0"))
      .join('')
      .match(/.{1,4}/g)
      .join('-')
}

console.log(uuid())
console.log(uuid())


5
我正在使用下面这个函数:
```javascript ```
function NewGuid()
{
    var sGuid = "";
    for (var i=0; i<32; i++)
    {
        sGuid += Math.floor(Math.random()*0xF).toString(0xF);
    }
    return sGuid;
}

4

如果有人在Google上寻找小型实用程序库,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


4

这个程序在底层使用了 Math.random(https://github.com/dustinpoissant/GUIDJS/blob/62c1dd3af36ea7e23194ac89386ca51ac2d4b541/src/GUID.js#L5)。因此,在浏览器中,如果 Math.random 实现不好,它可能会出现问题并且容易发生冲突。建议使用 uuid,因为它在可用的情况下使用了 crypto API。 - Mark Amery

3

在这里,您可以找到一个生成 UUID 的非常小的函数

其中的最终版本是:

function b(
  a                  // Placeholder
){
  var cryptoObj = window.crypto || window.msCrypto; // For Internet Explorer 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
      )
}

3

使用一个简单的uuid包很容易实现。 https://www.npmjs.com/package/uuid

const { v4: uuidv4 } = require('uuid');
uuidv4(); // ⇨ '1b9d6bcd-bbfd-4b2d-9b5d-ab8dfbbd4bed'

3
这里有一个函数,它可以从字符串生成静态UUID,如果没有提供字符串,则生成随机UUID:

function stringToUUID (str)
{
  if (str === undefined || !str.length)
    str = "" + Math.random() * new Date().getTime() + Math.random();

  let c = 0,
      r = "";

  for (let i = 0; i < str.length; i++)
    c = (c + (str.charCodeAt(i) * (i + 1) - 1)) & 0xfffffffffffff;

  str = str.substr(str.length / 2) + c.toString(16) + str.substr(0, str.length / 2);
  for(let i = 0, p = c + str.length; i < 32; i++)
  {
    if (i == 8 || i == 12 || i == 16 || i == 20)
      r += "-";

    c = p = (str[(i ** i + p + 1) % str.length]).charCodeAt(0) + p + i;
    if (i == 12)
      c = (c % 5) + 1; //1-5
    else if (i == 16)
      c = (c % 4) + 8; //8-B
    else
      c %= 16; //0-F

    r += c.toString(16);
  }
  return r;
}

console.log("Random       :", stringToUUID());
console.log("Static [1234]:", stringToUUID("1234")); //29c2c73b-52de-4344-9cf6-e6da61cb8656
console.log("Static [test]:", stringToUUID("test")); //e39092c6-1dbb-3ce0-ad3a-2a41db98778c

jsfiddle


3

基于@broofa的最高评价答案,这是一个最简单的JavaScript实现guid的方法,只需要3行代码。

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

当在控制台中执行时,会产生以下输出。 {{link1:输入图像描述}}


3
我已在此基础上构建了一些东西,产生了两倍的速度,适用于所有环境,包括Node,并从Math.random()升级到具有加密强度的随机性。您可能认为UUID不需要加密强度,但这意味着甚至更小的碰撞几率,这正是UUID的全部意义所在。
function random() {
    const
        fourBytesOn = 0xffffffff, // 4 bytes, all 32 bits on: 4294967295
        c = typeof crypto === "object"
            ? crypto // Node.js or most browsers
            : typeof msCrypto === "object" // Stinky non-standard Internet Explorer
                ? msCrypto // eslint-disable-line no-undef
                : null; // What old or bad environment are we running in?
        return c
            ? c.randomBytes
                ? parseInt(c.randomBytes(4).toString("hex"), 16) / (fourBytesOn + 1) - Number.EPSILON // Node.js
                : c.getRandomValues(new Uint32Array(1))[0] / (fourBytesOn + 1) - Number.EPSILON // Browsers
            : Math.random();
}

function uuidV4() { // eslint-disable-line complexity
    // If possible, generate a single random value, 128 bits (16 bytes)
    // in length. In an environment where that is not possible, generate
    // and make use of four 32-bit (4-byte) random values.
    // Use crypto-grade randomness when available, else Math.random()
    const
        c = typeof crypto === "object"
            ? crypto // Node.js or most browsers
            : typeof msCrypto === "object" // Stinky non-standard Internet Explorer
                ? msCrypto // eslint-disable-line no-undef
            : null; // What old or bad environment are we running in?
    let
        byteArray = c
            ? c.randomBytes
                ? c.randomBytes(16) // Node.js
                : c.getRandomValues(new Uint8Array(16)) // Browsers
            : null,
        uuid = [ ];

    /* eslint-disable no-bitwise */
    if ( ! byteArray) { // No support for generating 16 random bytes
                        // in one shot -- this will be slower
        const
            int = [
                random() * 0xffffffff | 0,
                random() * 0xffffffff | 0,
                random() * 0xffffffff | 0,
                random() * 0xffffffff | 0
            ];
        byteArray = [ ];
        for (let i = 0; i < 256; i++) {
            byteArray[i] = int[i < 4 ? 0 : i < 8 ? 1 : i < 12 ? 2 : 3] >> i % 4 * 8 & 0xff;
        }
    }
    byteArray[6] = byteArray[6] & 0x0f | 0x40; // Always 4, per RFC, indicating the version
    byteArray[8] = byteArray[8] & 0x3f | 0x80; // Constrained to [89ab], per RFC for version 4
    for (let i = 0; i < 16; ++i) {
        uuid[i] = (byteArray[i] < 16 ? "0" : "") + byteArray[i].toString(16);
    }
    uuid =
        uuid[ 0] + uuid[ 1] + uuid[ 2] + uuid[ 3] + "-" +
        uuid[ 4] + uuid[ 5]                       + "-" +
        uuid[ 6] + uuid[ 7]                       + "-" +
        uuid[ 8] + uuid[ 9]                       + "-" +
        uuid[10] + uuid[11] + uuid[12] + uuid[13] + uuid[14] + uuid[15];
    return uuid;
    /* eslint-enable no-bitwise */
}

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接