如何在JavaScript中创建GUID(全球独特识别器)?GUID/UUID应该至少有32个字符,并且应该保持在ASCII范围内,以避免在通过它们时遇到麻烦。

我不确定在所有浏览器上有哪些习惯,如何“随机”和种植内置的随机号码发电机等。


当前回答

一个简单的解决方案来创建一个独特的识别是使用一个时间标记,并添加一个随机号码。

下面的功能将产生类型的随机序列: uuid-14d93eb1b9b4533e6. 不需要产生32个字符的随机序列. 在这种情况下,16个字符的随机序列不足以提供JavaScript中的独特 UUID。

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

其他回答

下面是顶级投票答案的组合,与Chrome的冲突工作组合:

generateGUID = (typeof(window.crypto) != 'undefined' &&
                typeof(window.crypto.getRandomValues) != 'undefined') ?
    function() {
        // If we have a cryptographically secure PRNG, use that
        // https://stackoverflow.com/questions/6906916/collisions-when-generating-uuids-in-javascript
        var buf = new Uint16Array(8);
        window.crypto.getRandomValues(buf);
        var S4 = function(num) {
            var ret = num.toString(16);
            while(ret.length < 4){
                ret = "0"+ret;
            }
            return ret;
        };
        return (S4(buf[0])+S4(buf[1])+"-"+S4(buf[2])+"-"+S4(buf[3])+"-"+S4(buf[4])+"-"+S4(buf[5])+S4(buf[6])+S4(buf[7]));
    }

    :

    function() {
        // Otherwise, just use Math.random
        // https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript/2117523#2117523
        return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {
            var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);
            return v.toString(16);
        });
    };

这是在Jsbin,如果你想测试它。

下面是2011年10月9日的解决方案,由用户在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
      )
}

下面是使用 crypto.getRandomValues(a)在支持的浏览器(Internet Explorer 11+,iOS 7+,Firefox 21+,Chrome,和Android Chrome)的简单代码。

它避免使用Math.random(),因为这可能会导致碰撞(例如,在 Muxa 实际情况下产生 4000 UUID 的 20 次碰撞)。

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 每秒. 它在我的笔记本电脑上在 Chromium 中每秒产生约 10000 uuid() 用 http://jsbin.com/fuwigo/1 来测量性能. 它只使用 8 为 “y” 因为它简化了代码可读性(y 允许为 8, 9, A 或 B)。

因此,注意到这篇文章有超过30个答案,这里是...... 这篇文章有:一个“TL;DR”代码部分w/自含的es6类 Xuid一个使用案例和动机讨论部分关于es6类 Xuid提供代码。

class Xuid {
  //@ edges.sm.st, ess.dev: MIT license Smallscript/David Simmons 2020
  //! Can't use `static const field = const` xbrowser (thus, const's duped)
  static get v4New() {
    const ns7Now = this.ns7Now, xnode48 = this.xnode48; let clock_seq13
    // monotonic `clock_seq` guarantee (13-bits/time-quantum)
    if(ns7Now <= this.ns7Now_prevSeq && this.ns7Now_prevSeq)
      clock_seq13 = ((this.ns7Now_prevSeq += 1n) - ns7Now) & 0b1_1111_1111_1111n
    else
      clock_seq13 = 0n, this.ns7Now_prevSeq = ns7Now
    const time60 = ((ns7Now << 4n) & 0xFFFF_FFFF_FFFF_0000n) |
                           (ns7Now & 0x0000_0000_0000_0FFFn),
              v4 = 0x1_00000000_0000_0000_0000_000000000000n |
      (time60 << 64n) | (0x00000000_0000_4000_0000_000000000000n) | // M: V4
      (0b110n << 61n) | (clock_seq13 << 48n) | // N: Variant-2 time-seq collation
      xnode48, s = v4.toString(16)//.substr(1)
    return `{${s.substr(1,8)}-${s.substr(9,4)}-${s.substr(13,4)}-${
      s.substr(17,4)}-${s.substr(21,12)}}`
  }
  static get xnode48()/*:<BigInt#48>*/{
    if(this.xnode48_) return this.xnode48_
    let clockSeqNode; if(typeof URL !== 'undefined' && URL.createObjectURL) {
      const url = URL.createObjectURL(new Blob())
      const id = (url.toString().split('/').reverse()[0]).split('-')
      URL.revokeObjectURL(url)
      clockSeqNode = BigInt('0x'+id[3]+id[4])
    }
    else {
      const a4 = this.a4; this.getRandomValues(this.a4);
      clockSeqNode = (BigInt(a4[2]) << 32n) | BigInt(a4[3])
    }
    // simulate the 48-bit node-id and 13-bit clock-seq
    // to combine with 3-bit uuid-variant
    return this.xnode48_ = clockSeqNode & 0xFFFF_FFFF_FFFFn;
  }
  static get jdNow()/*:<double#ns7>*/{
    // return 2440587.5+Date.now()/864e5 // <- Date-quantum-ms form (7ns form below)
    return this.jdFromNs7(this.ns7Now)
  }
  static get ns7Now()/*:<BigInt#60>*/{
    if(typeof performance !== 'undefined' && performance.now)
      Reflect.defineProperty(this, 'ns7Now',
        Reflect.getOwnPropertyDescriptor(this,'ns7Now_performance'))
    else
      Reflect.defineProperty(this, 'ns7Now',
        Reflect.getOwnPropertyDescriptor(this, 'ns7Now_Date'))
    return this.ns7Now
  }
  static get ns7Now_Date()/*:<BigInt#60>*/{
    // const epoch1582Ns7_bias = 0x1b2_1dd2_1381_4000  // V1 1582 Oct 15
    // const epoch1601Ns7_bias = 0x19d_b1de_d53e_8000n // FILETIME base
    const epoch1970Ns7 = BigInt(Date.now() * 1000_0.0)
    return epoch1970Ns7 + 0x1b2_1dd2_1381_4000n
  }
  static get ns7Now_performance()/*:<BigInt#60>*/{
    const epochPgNs7 = BigInt(performance.now()*/*15*/1000_0.0|/*17*/0)
    if(!this.epoch1970PgNs7) // performance.timing.navigationStart
      this.epoch1970PgNs7 = this.ns7Now_Date - epochPgNs7
    return epochPgNs7 + this.epoch1970PgNs7
  }
  static dateFromJd(jd) {return new Date((jd - 2440587.5) * 864e5)}
  static dateFromNs7(ns7) {
    return new Date(Number(ns7 - 0x1b2_1dd2_1381_4000n) / 1000_0.0)}
  static jdFromNs7(ns7) {   // atomic-clock leap-seconds (ignored)
    return 2440587.5 + (Number(ns7 - 0x1b2_1dd2_1381_4000n) / 864e9)
  }
  static ns7FromJd(jd) {
    return BigInt((jd - 2440587.5) * 864e9) + 0x1b2_1dd2_1381_4000n
  }
  static getRandomValues(va/*:<Uint32Array>*/) {
    if(typeof crypto !== 'undefined' && crypto.getRandomValues)
      crypto.getRandomValues(va)
    else for(let i = 0, n = va.length; i < n; i += 1)
      va[i] = Math.random() * 0x1_0000_0000 >>> 0
  }
  static get a4() {return this.a4_ || (this.a4_ = new Uint32Array(4))}
  static ntohl(v)/*:<BigInt>*/{
    let r = '0x', sign = 1n, s = BigInt(v).toString(16)
    if(s[0] == '-') s = s.substr(1), sign = -1n
    for(let i = s.length; i > 0; i -= 2)
      r += (i == 1) ? ('0' + s[i-1]) : s[i-2] + s[i-1]
    return sign*BigInt(r)
  }
  static ntohl32(v)/*:<Number>*/{return Number(this.ntohl(v))}
}

总结

雖然有,但我希望這對現在有足夠的解釋;試試。

在GitHub上发布 EdgeS Web-Client Eswc 图书馆的一部分时, indexedDb 使用模式与 efs 将作为其设计意图的示例,其中包括处理效率和可用性与 indexedDb 和相关 PWA 同步和复制场景。

Related

朱利安日计算在JavaScript中

基准评分 Novids/sec

const start = Xuid.ns7Now
for(let i = 100000; i; i -=1)
  Xuid.v4New
const end = Xuid.ns7Now
console.log(`Delta 7ns: ${(end-start)/100000n}`)

这创建了一个版本 4 UUID (创建于假冒随机数字):

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