[javascript] How to create a GUID / UUID

I'm trying to create globally-unique identifiers in JavaScript. I'm not sure what routines are available on all browsers, how "random" and seeded the built-in random number generator is, etc.

The GUID / UUID should be at least 32 characters and should stay in the ASCII range to avoid trouble when passing them around.

This question is related to javascript guid uuid

The answer is


For science. I haven't seen anyone do this yet... its not v4 compliant, but could easily be altered to be. Its just an example of extending the Uint8Array type, and using crypto.getRandomValues() to generate the uuid byte values.

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

You can use node-uuid (https://github.com/kelektiv/node-uuid)

Simple, fast generation of RFC4122 UUIDS.

Features:

  • Generate RFC4122 version 1 or version 4 UUIDs
  • Runs in node.js and browsers.
  • Cryptographically strong random # generation on supporting platforms.
  • Small footprint (Want something smaller? Check this out!)

Install Using NPM:

npm install uuid

Or Using uuid via browser:

Download Raw File (uuid v1): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v1.js Download Raw File (uuid v4): https://raw.githubusercontent.com/kelektiv/node-uuid/master/v4.js


Want even smaller? Check this out: https://gist.github.com/jed/982883


Usage:

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

I know, it is an old question. Just for completeness, if your environment is SharePoint, there is a utility function called SP.Guid.newGuid (MSDN link which creates a new GUID. This function is inside the sp.init.js file. If you rewrite this function (to remove some other dependencies from other private functions), it looks like this:

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

This one is based on date, and add a random suffix to "ensure" uniqueness. Works well for css identifiers. It always returns something like and is easy to hack:

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

Here's a solution dated Oct. 9, 2011 from a comment by user jed at 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)}

This accomplishes the same goal as the current highest-rated answer, but in 50+ fewer bytes by exploiting coercion, recursion, and exponential notation. For those curious how it works, here's the annotated form of an older version of the function:

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

Here's some code based on RFC 4122, section 4.4 (Algorithms for Creating a UUID from Truly Random or Pseudo-Random Number).

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

If you just need a random 128 bit string in no particular format you can use:

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

Which will return something like 2350143528-4164020887-938913176-2513998651.


UUID with timestamp built in (emitter/parser)
I will also post my simple approach to generating a valid UUID v4 with very strong uniqueness and fast runtime. The basic idea is not new, but approach is different. I use a timestamp in milliseconds from the date.now() (in Node.js library, which I'll point later, I use nanoseconds timestamp from process.hrtime.bigint()), and then add a random 5 digit number (10000-90000) to the end of the timestamp string. After merging the strings, I just form a valid UUID from digits and a pair of special characters, so that my UUID consists only of digits and a few non-numeric characters. Please check it out below:

_x000D_
_x000D_
/*
 * uuid-timestamp (emitter)
 * UUID v4 based on timestamp
 *
 * Created by tarkh
 * tarkh.com (C) 2020
 */
const uuidEmit = () => {
  // Get now time
  const n = Date.now();
  // Generate random
  const r = Math.random();
  // Stringify now time and generate additional random number
  const s = String(n) + String(~~(r*9e4)+1e4);
  // Form UUID and return it
  return `${s.slice(0,8)}-${s.slice(8,12)}-4${s.slice(12,15)}-${[8,9,'a','b'][~~(r*3)]}${s.slice(15,18)}-${s.slice(s.length-12)}`;
};

// Generate 5 UUIDs
console.log(`${uuidEmit()}
${uuidEmit()}
${uuidEmit()}
${uuidEmit()}
${uuidEmit()}`);
_x000D_
_x000D_
_x000D_

Looking at the results, you obviously see that the first part of UUIDs is the same, and then comes randomness. This is because I inserted the timestamp into the UUID linearly. The code will produce a new UUID every millisecond (nanosecond in Node.js library) + add a random 5-digit number to the end, so we end up with very approximate collision probability around 1 in 10 million per second. If we use Node.js library, our very approximate collision probability goes to 1 in 10 billion per second.

Timestamp built into the UUID
Since we insert a timestamp into the UUID linearly, we get a feature (good or bad - depends on the task) - ability to easily extract this timestamp back from the UUID. This way we can understand when UUID was released:

_x000D_
_x000D_
/*
 * uuid-timestamp (parser)
 * UUID v4 based on timestamp
 *
 * Created by tarkh
 * tarkh.com (C) 2020
 */
const uuidParse = (uuid) => {
  // Get current timestamp string length
  let tl = String(Date.now()).length;
  // Strip out timestamp from UUID
  let ts = '';
  let i = -1;
  while(tl--) {
    i++;
    if(i===8||i===13||i===14||i===18||i===19||i===23) {
      tl++;
      continue;
    }
    ts += uuid[i];
  }
  return Number(ts);
};

// Get the timestamp when UUID was emitted
const time = uuidParse('15970688-7109-4530-8114-887109530114');

// Covert timestamp to date and print it
console.log(new Date(time).toUTCString());
_x000D_
_x000D_
_x000D_

Node.js
NPM version of my code above available as Node.js module. This version is even more powerful in generating unique values, because instead of millisecond timestamp it uses nanoseconds from combination of system time and process.hrtime.bigint() diff.

Benchmarks
At the end of my post, I want to do some performance tests based on some of the answers from this topic. Of course, my decision is not the fastest, but it certainly takes the top positions.
Check jsBench here


Here is a function that converts any string into "static" UUID or generate a random UUID if no string supplied:

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

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

  str = (c).toString(16) + str;
  let p = str.length;
  return 'xxxxxxxx-xxxx-mxxx-nxxx-xxxxxxxxxxxx'.replace(/[xmn]/g, function (c, i, s)
  {
    s = p = (str[(i ** i + p + 1) % str.length]).charCodeAt(0) + p + i;
    if (c == "x")
      s %= 16; //0-F
    else if (c == "m")
      s = (s % 4) + 1; //1-5
    else
      s = (s % 4) + 8; //8-B

    return s.toString(16);
  });
}


console.log("Random       :", stringToUUID());
console.log("Static [1234]:", stringToUUID("1234")); //8f282d91-c746-2568-9b1a-8501fee1247b
console.log("Static [test]:", stringToUUID("test")); //a07f91b8-5544-39c1-a4d6-41ef0258b05c
_x000D_
_x000D_
_x000D_

jsfiddle


This is just a concept, which most certainly can be improved in many ways, but isn't that slow as I thought it would be.

In general, this code includes hex encoded timestamp in milliseconds (with some hacking it gives 12 digits, so the code will work even after 2527-06-24, but not after 5138-11-16), which means it's sortable. It's not that random, it uses MAC address for last 12 digits. 13th letter is hard coded 1, to keep it sortable.

After that, next 6 digits come from semi-random string, where first digits come from count of records generated on that millisecond, and other digits are randomly generated. That 6-digit portion contains a dash, and hard coded letter 'a', to keep records sortable.

I know this could be shortened, and performance improved, but I'm happy with results (except the mac address)

_x000D_
_x000D_
currentNanoseconds = () => {
  return nodeMode ? process.hrtime.bigint() : BigInt(Date.now() * 1000000);
}

nodeFindMacAddress = () => {
  // extract MAC address
  const interfaces = require('os').networkInterfaces();
  let result = null;
  for (index in interfaces) {
    let entry = interfaces[index];
    entry.forEach(item => {
      if (item.mac !== '00:00:00:00:00:00') {
        result = '-' + item.mac.replace(/:/g, '');
      }
    });
  }
  return result;
}

const nodeMode = typeof(process) !== 'undefined';
let macAddress = nodeMode ? nodeFindMacAddress() : '-a52e99ef5efc';
let startTime = currentNanoseconds();


let uuids = []; // array for storing generated uuids, useful for testing
let currentTime = null; // holds the last value of Date.now(), used as base for generating uuid
let timePart = null; // part of uuid generated from Date.now()
let counter = 0; // used for counting records created at certain millisecond
let lastTime = null; // used for resetting record counter

const limit = 1000000;

for (let testCounter = 0; testCounter < limit; testCounter++) {
  let uuid = testMe();

  if (nodeMode || testCounter <= 50) {
    uuids.push(uuid);
  }
}

const timePassed = Number(currentNanoseconds() - startTime);

if (nodeMode) {
  const fs = require('fs');
  fs.writeFileSync('temp.txt', JSON.stringify(uuids).replace(/,/g, ',\n'));
} else {
  console.log(uuids);
}

console.log({
  operationsPerSecond: (1000 * limit / timePassed).toString() + 'm',
  nanosecondsPerCycle: timePassed / limit,
  milliSecondsPassed: timePassed / 1000000,
  microSecondsPassed: timePassed / 1000,
  nanosecondsPassed: timePassed
});

function testMe() {
  currentTime = Date.now();
  let uuid = null; // function result

  if (currentTime !== lastTime) {
    // added a 9 before timestamp, so that hex encoded timestamp is 12 digits long, currently it is 11 digits long, and it will be until 2527-06-24
    // console.log(Date.parse("2527-06-24").toString(16).length)
    // code will stop working on 5138-11-17, because the timestamp will be 15 digits long, and code only handels upto 14 digit timestamps
    // console.log((Date.parse("5138-11-17")).toString().length)
    timePart = parseInt(('99999999999999' + currentTime).substr(-14)).toString(16);
    timePart = timePart.substr(0, 8) + '-' + timePart.substr(8, 4) + '-1';
    counter = 0;
  }

  randomPart = ('000000' + Math.floor(10 * (counter + Math.random()))).slice(-6);
  randomPart = randomPart.substr(0, 3) + '-a' + randomPart.substr(3, 3);
  uuid = timePart + randomPart + macAddress;

  counter++;

  lastTime = currentTime;

  return uuid;

}
_x000D_
_x000D_
_x000D_


A typescript version of broofa's update from 2017-06-28, based on crypto API:

function genUUID() {
        // Reference: https://stackoverflow.com/a/2117523/709884
        return ("10000000-1000-4000-8000-100000000000").replace(/[018]/g, s => {
            const c = Number.parseInt(s, 10)
            return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
        })
}

Reasons:

  • Use of + between number[] and number isn't valid
  • The conversion from string to number has to be explicit

From sagi shkedy's technical blog:

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

There are other methods that involve using an ActiveX control, but stay away from these!

I thought it was worth pointing out that no GUID generator can guarantee unique keys (check the Wikipedia article). There is always a chance of collisions. A GUID simply offers a large enough universe of keys to reduce the change of collisions to almost nil.


JavaScript project on GitHub - https://github.com/LiosK/UUID.js

UUID.js The RFC-compliant UUID generator for JavaScript.

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

Features Generates RFC 4122 compliant UUIDs.

Version 4 UUIDs (UUIDs from random numbers) and version 1 UUIDs (time-based UUIDs) are available.

UUID object allows a variety of access to the UUID including access to the UUID fields.

Low timestamp resolution of JavaScript is compensated by random numbers.


I found this script useful for creating GUIDs in JavaScript

https://github.com/addui/GUIDJS

var myGuid = GUID();

The better way:

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,
                  ?              // generate 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
 }

Minimized:

function(a,b){for(b=a='';a++<36;b+=a*51&52?(a^15?8^Math.random()*(a^20?16:4):4).toString(16):'-');return b}

var guid = createMyGuid();

function createMyGuid()  
{  
   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);  
   });  
}

Necromancing.

Effectively, a Guid, or UUID as it is called in non-microsoft-circles, is just a 128-Bit cryptographic random number, with the uuid version number (1-5) being at a fixed location byte.

So when you just generate a bunch of random numbers betwween 0 and 65535 and hex-encode them, like this:

function guid()
{
    function s4()
    {
        return Math.floor(Math.random() * 65536).toString(16).padStart(4, '0')
    } // End Function s4 

    return s4() + s4() + '-' + s4() + '-' + "4" + s4().substr(1) + '-' + s4() + '-' + s4() + s4() + s4();
} // End Function guid 

you get a valid GUID, but due to the random-implementation, it's not cryptographically secure.

To generate a cryptographically secure GUID, you need to use window.crypto (or window.msCrypto for Internet Exploder).

That goes like this:

function cryptGuid()
{ 
    var array = new Uint16Array(8);
    (window.crypto || window.msCrypto).getRandomValues(array);
    var dataView = new DataView(array.buffer);
    
    var parts = [];

    for(var i = 0; i < array.length; ++i)
    {
        // 0&1,2,3,4,5-7 dataView.getUint16(0-7)
        if(i>1 && i<6) parts.push("-");
        parts.push(dataView.getUint16(i).toString(16).padStart(4, '0'));
    }

    parts[5] = "4" + parts[5].substr(1);
    // console.log(parts);
    return parts.join('').toUpperCase();// .toLowerCase();
}

cryptGuid();

Plus you have to decide, if you return the number as lower-or upper-case character string. Certain software require lowercase characters (e.g. Reporting Service), while others generate uppercase characters (SQL-Server).


This creates a version 4 UUID (created from pseudo random numbers):

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

Here is a sample of the UUIDs generated:

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

broofa's answer is pretty slick, indeed - impressively clever, really... rfc4122 compliant, somewhat readable, and compact. Awesome!

But if you're looking at that regular expression, those many replace() callbacks, toString()'s and Math.random() function calls (where he's only using 4 bits of the result and wasting the rest), you may start to wonder about performance. Indeed, joelpt even decided to toss out RFC for generic GUID speed with generateQuickGUID.

But, can we get speed and RFC compliance? I say, YES! Can we maintain readability? Well... Not really, but it's easy if you follow along.

But first, my results, compared to broofa, guid (the accepted answer), and the non-rfc-compliant 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.

So by my 6th iteration of optimizations, I beat the most popular answer by over 12X, the accepted answer by over 9X, and the fast-non-compliant answer by 2-3X. And I'm still rfc4122 compliant.

Interested in how? I've put the full source on http://jsfiddle.net/jcward/7hyaC/3/ and on http://jsperf.com/uuid-generator-opt/4

For an explanation, let's start with broofa's code:

_x000D_
_x000D_
function broofa() {_x000D_
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {_x000D_
        var r = Math.random()*16|0, v = c == 'x' ? r : (r&0x3|0x8);_x000D_
        return v.toString(16);_x000D_
    });_x000D_
}_x000D_
_x000D_
console.log(broofa())
_x000D_
_x000D_
_x000D_

So it replaces x with any random hex digit, y with random data (except forcing the top 2 bits to 10 per the RFC spec), and the regex doesn't match the - or 4 characters, so he doesn't have to deal with them. Very, very slick.

The first thing to know is that function calls are expensive, as are regular expressions (though he only uses 1, it has 32 callbacks, one for each match, and in each of the 32 callbacks it calls Math.random() and v.toString(16)).

The first step toward performance is to eliminate the RegEx and its callback functions and use a simple loop instead. This means we have to deal with the - and 4 characters whereas broofa did not. Also, note that we can use String Array indexing to keep his slick String template architecture:

_x000D_
_x000D_
function e1() {_x000D_
    var u='',i=0;_x000D_
    while(i++<36) {_x000D_
        var c='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'[i-1],r=Math.random()*16|0,v=c=='x'?r:(r&0x3|0x8);_x000D_
        u+=(c=='-'||c=='4')?c:v.toString(16)_x000D_
    }_x000D_
    return u;_x000D_
}_x000D_
_x000D_
console.log(e1())
_x000D_
_x000D_
_x000D_

Basically, the same inner logic, except we check for - or 4, and using a while loop (instead of replace() callbacks) gets us an almost 3X improvement!

The next step is a small one on the desktop but makes a decent difference on mobile. Let's make fewer Math.random() calls and utilize all those random bits instead of throwing 87% of them away with a random buffer that gets shifted out each iteration. Let's also move that template definition out of the loop, just in case it helps:

_x000D_
_x000D_
function e2() {_x000D_
    var u='',m='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx',i=0,rb=Math.random()*0xffffffff|0;_x000D_
    while(i++<36) {_x000D_
        var c=m[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);_x000D_
        u+=(c=='-'||c=='4')?c:v.toString(16);rb=i%8==0?Math.random()*0xffffffff|0:rb>>4_x000D_
    }_x000D_
    return u_x000D_
}_x000D_
_x000D_
console.log(e2())
_x000D_
_x000D_
_x000D_

This saves us 10-30% depending on platform. Not bad. But the next big step gets rid of the toString function calls altogether with an optimization classic - the look-up table. A simple 16-element lookup table will perform the job of toString(16) in much less time:

_x000D_
_x000D_
function e3() {_x000D_
    var h='0123456789abcdef';_x000D_
    var k='xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx';_x000D_
    /* same as e4() below */_x000D_
}_x000D_
function e4() {_x000D_
    var h=['0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'];_x000D_
    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'];_x000D_
    var u='',i=0,rb=Math.random()*0xffffffff|0;_x000D_
    while(i++<36) {_x000D_
        var c=k[i-1],r=rb&0xf,v=c=='x'?r:(r&0x3|0x8);_x000D_
        u+=(c=='-'||c=='4')?c:h[v];rb=i%8==0?Math.random()*0xffffffff|0:rb>>4_x000D_
    }_x000D_
    return u_x000D_
}_x000D_
_x000D_
console.log(e4())
_x000D_
_x000D_
_x000D_

The next optimization is another classic. Since we're only handling 4-bits of output in each loop iteration, let's cut the number of loops in half and process 8-bits each iteration. This is tricky since we still have to handle the RFC compliant bit positions, but it's not too hard. We then have to make a larger lookup table (16x16, or 256) to store 0x00 - 0xff, and we build it only once, outside the e5() function.

_x000D_
_x000D_
var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }_x000D_
function e5() {_x000D_
    var k=['x','x','x','x','-','x','x','-','4','x','-','y','x','-','x','x','x','x','x','x'];_x000D_
    var u='',i=0,rb=Math.random()*0xffffffff|0;_x000D_
    while(i++<20) {_x000D_
        var c=k[i-1],r=rb&0xff,v=c=='x'?r:(c=='y'?(r&0x3f|0x80):(r&0xf|0x40));_x000D_
        u+=(c=='-')?c:lut[v];rb=i%4==0?Math.random()*0xffffffff|0:rb>>8_x000D_
    }_x000D_
    return u_x000D_
}_x000D_
_x000D_
console.log(e5())
_x000D_
_x000D_
_x000D_

I tried an e6() that processes 16-bits at a time, still using the 256-element LUT, and it showed the diminishing returns of optimization. Though it had fewer iterations, the inner logic was complicated by the increased processing, and it performed the same on desktop, and only ~10% faster on mobile.

The final optimization technique to apply - unroll the loop. Since we're looping a fixed number of times, we can technically write this all out by hand. I tried this once with a single random variable r that I kept re-assigning, and performance tanked. But with four variables assigned random data up front, then using the lookup table, and applying the proper RFC bits, this version smokes them all:

_x000D_
_x000D_
var lut = []; for (var i=0; i<256; i++) { lut[i] = (i<16?'0':'')+(i).toString(16); }_x000D_
function e7()_x000D_
{_x000D_
    var d0 = Math.random()*0xffffffff|0;_x000D_
    var d1 = Math.random()*0xffffffff|0;_x000D_
    var d2 = Math.random()*0xffffffff|0;_x000D_
    var d3 = Math.random()*0xffffffff|0;_x000D_
    return lut[d0&0xff]+lut[d0>>8&0xff]+lut[d0>>16&0xff]+lut[d0>>24&0xff]+'-'+_x000D_
    lut[d1&0xff]+lut[d1>>8&0xff]+'-'+lut[d1>>16&0x0f|0x40]+lut[d1>>24&0xff]+'-'+_x000D_
    lut[d2&0x3f|0x80]+lut[d2>>8&0xff]+'-'+lut[d2>>16&0xff]+lut[d2>>24&0xff]+_x000D_
    lut[d3&0xff]+lut[d3>>8&0xff]+lut[d3>>16&0xff]+lut[d3>>24&0xff];_x000D_
}_x000D_
_x000D_
console.log(e7())
_x000D_
_x000D_
_x000D_

Modualized: http://jcward.com/UUID.js - UUID.generate()

The funny thing is, generating 16 bytes of random data is the easy part. The whole trick is expressing it in String format with RFC compliance, and it's most tightly accomplished with 16 bytes of random data, an unrolled loop and lookup table.

I hope my logic is correct -- it's very easy to make a mistake in this kind of tedious bit-work. But the outputs look good to me. I hope you enjoyed this mad ride through code optimization!

Be advised: my primary goal was to show and teach potential optimization strategies. Other answers cover important topics such as collisions and truly random numbers, which are important for generating good UUIDs.


I wanted to understand broofa's answer, so I expanded it and added comments:

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

For those wanting an RFC 4122 version 4 compliant solution with speed considerations (few calls to Math.random()):

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

The above function should have a decent balance between speed and randomness.


Here you can find a very small function that generates uuids https://gist.github.com/jed/982883

One of the final versions is:

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

You could use the npm package guid, a guid generator and validator.

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

Example:

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

UPDATE: This package has been deprecated. Use uuid instead.

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

Example:

const uuidv4 = require('uuid/v4');
uuidv4(); // ? '10ba038e-48da-487b-96e8-8d3b99b6d18a'

For an RFC4122 version 4 compliant solution, this one-liner(ish) solution is the most compact I could come up with:

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

Update, 2015-06-02: Be aware that UUID uniqueness relies heavily on the underlying random number generator (RNG). The solution above uses Math.random() for brevity, however Math.random() is not guaranteed to be a high-quality RNG. See Adam Hyland's excellent writeup on Math.random() for details. For a more robust solution, consider using the uuid module, which uses higher quality RNG APIs.

Update, 2015-08-26: As a side-note, this gist describes how to determine how many IDs can be generated before reaching a certain probability of collision. For example, with 3.26x1015 version 4 RFC4122 UUIDs you have a 1-in-a-million chance of collision.

Update, 2017-06-28: A good article from Chrome developers discussing the state of Math.random PRNG quality in Chrome, Firefox, and Safari. tl;dr - As of late-2015 it's "pretty good", but not cryptographic quality. To address that issue, here's an updated version of the above solution that uses ES6, the crypto API, and a bit of JavaScript wizardry I can't take credit for:

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

Update, 2020-01-06: There is a proposal in the works for a standard uuid module as part of the JavaScript language


Just another more readable variant with just two mutations.

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

The native URL.createObjectURL is generating an uuid. You can take advantage of this.

function uuid() {
  const url = URL.createObjectURL(new Blob())
  const [id] = url.toString().split('/').reverse()
  URL.revokeObjectURL(url)
  return id
}

It is important that to use well tested code that is maintained by more than 1 contributors instead of whipping your own stuff for this. This is one of the places where you probably want to prefer most stable code than shortest possible clever version that works in X browser but doesn't take in to account idiosyncrasies of Y which would often lead to very hard to investigate bugs than manifests only randomly for some users. Personally I use uuid-js at https://github.com/aurigadl/uuid-js which bower enabled so I can take updates easily.


Well, this has a bunch of answers already, but unfortunately there's not a "true" random in the bunch. The version below is an adaptation of broofa's answer, but updated to include a "true" random function that uses crypto libraries where available, and the Alea() function as a fallback.

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

OK, using uuid package, it support for version 1, 3, 4 and 5 UUIDs do:

yarn add uuid

and then:

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

You can also do it with fully-specified options:

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'

For more info, visit the npm page here


We can use replace and crypto.getRandomValues to get an output like this :

xxxxxxxx-xxxx-4xxx-xxxx-xxxxxxxxxxxx

enter image description here

If we are looking for an opti solution, we have to replace crypto.getRandomValues(new Uint8Array(1))[0] by an array(32).

const uuidv4 = () =>
  ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
    (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & 15 >> c / 4).toString(16)
  );

console.log(uuidv4());

To get this code :

_x000D_
_x000D_
function uuidv4() {_x000D_
  let bytes = window.crypto.getRandomValues(new Uint8Array(32));_x000D_
  const randomBytes = () => (bytes = bytes.slice(1)) && bytes[0];_x000D_
_x000D_
  return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c => _x000D_
      (c ^ randomBytes() & 15 >> c / 4).toString(16)_x000D_
    );_x000D_
}_x000D_
_x000D_
_x000D_
for (var i = 0; i < 10; i++)_x000D_
  console.log(uuidv4());
_x000D_
_x000D_
_x000D_

Collision :

We can do like google analytics and add a timestamp with : uuidv4() + "." + (+new Date()).


The following uuid implementation offers a different ES6 2020 solution using BigInt and focuses on "Use case intent for a uuid design pattern"; especially for use with indexedDb primaryKey scenarios where unifying sequencing in time and collation are valuable.

So, noting that this post has over 30 answers, here goes...

This post has:

  1. a "TL;DR" code section w/self-contained es6 class Xuid
  2. a use-case and motivations discussion section regarding the es6 class Xuid provided code.

TL;DR class Xuid solution for generic v4 uuid using a monotonic clock

The code-below is extracted from Smallscript's EdgeS web-client library that I wrote and own and is provided here, freely MIT licensed. A github version will be available once EdgeS web-client toolset is released.

Usage example:

eval: console.log(Xuid.v4New)
emits: {1eb4a659-8bdc-4ce0-c002-b1d505d38ea8}

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

Motivation

While v4 uuid defines a basically random uuid, it is desirable to have a uuid implementation that can support some additional characteristics.

  • creates new uuid values quickly and efficiently (using BigInt)
  • implemented as standalone code with a nominal 80 loc readable class w/comments
  • incorporates uuid uniqueness using monotonic time within a context
  • stringifies such that the string form:
    • collates based on time and then context (using uuid Variant-2)
    • converts back to a binary form that correctly identifies and recovers the time
  • incorporates JavaScript micro-second clock accuracy where available
  • supports cross-environment quantum of 100 nano-second units based on julian-day epoch year 1582 Oct 15, V1 compatibility. Choices that enable unified time behavior across a spectrum of environments and use cases consistent with EdgeS and ESS language model.

    Especially suited for database use with facilities like SqLite.

  • uses es6 class design to simplify extensibility for nominal work to extend it to provide other uuid variants
  • for this posting, unified and incorporated basic time and related eswc library APIs.
    • Julian Day api
    • ns7 (100 nano-second quantum) api
    • ntohl api for endian convenience re-ordering BigInt string representations
  • derived from QKS Smalltalk 1991, AOS® [Agile Object System;Agents Object System] engine family technology for language, framework and runtimes it preserves use case compatibility across a wide range of current and historical host OS models.
    • specifically where the Xuid curly-brace quoted scalar string format supports guid, uuid, and uid (git, fossil, SqLite repo-id) representations, FILETIME etc.

      as in: {1eb4a659-8bdc-4ce0-c002-b1d505d38ea8}

  • last, but not least, it provides a desirable solution to working with indexedDb object stores where using a uuid as the primaryKey becomes desireable.
    • enabling auto-sequencing capabilities
    • natural string collation
      • note the subtle use of uuid Variant-2 to reverse time value of the LHS in its stringified form.
    • natural and simple put updating
    • natural pattern for efs (EdgeS virtual file-system auto-names)
    • service-worker and cloud-server sync and replicate actions

Summary

Although terse, hopefully that is sufficient explanation for now; try it

And, please feel free to comment, submit feedback or suggestions.

When released as part of the EdgeS web-client eswc library on github the indexedDb usage patterns with efs will serve as examples of its design intentions which include addressing efficiencies and usability with indexedDb and related PWA sync and replicate scenarios.

Related

Benchmarking uuids/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}`)

Resulted in: values of 16..20 => ~2 micro-seconds => 500,000 uuids/sec


Simple JavaScript module as a combination of best answers in this question.

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

Usage:

Guid.newGuid()

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

Guid.empty

"00000000-0000-0000-0000-000000000000"


Fastest GUID like string generator method in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. This does not generate standard-compliant GUID.

Ten million executions of this implementation take just 32.5 seconds, which is the fastest I've ever seen in a browser (the only solution without loops/iterations).

The function is as simple as:

/**
 * Generates a GUID string.
 * @returns {string} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser.
 * @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();
}

To test the performance, you can run this code:

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

I'm sure most of you will understand what I did there, but maybe there is at least one person that will need an explanation:

The algorithm:

  • The Math.random() function returns a decimal number between 0 and 1 with 16 digits after the decimal fraction point (for example 0.4363923368509859).
  • Then we take this number and convert it to a string with base 16 (from the example above we'll get 0.6fb7687f).
    Math.random().toString(16).
  • Then we cut off the 0. prefix (0.6fb7687f => 6fb7687f) and get a string with eight hexadecimal characters long.
    (Math.random().toString(16).substr(2,8).
  • Sometimes the Math.random() function will return shorter number (for example 0.4363), due to zeros at the end (from the example above, actually the number is 0.4363000000000000). That's why I'm appending to this string "000000000" (a string with nine zeros) and then cutting it off with substr() function to make it nine characters exactly (filling zeros to the right).
  • The reason for adding exactly nine zeros is because of the worse case scenario, which is when the Math.random() function will return exactly 0 or 1 (probability of 1/10^16 for each one of them). That's why we needed to add nine zeros to it ("0"+"000000000" or "1"+"000000000"), and then cutting it off from the second index (3rd character) with a length of eight characters. For the rest of the cases, the addition of zeros will not harm the result because it is cutting it off anyway.
    Math.random().toString(16)+"000000000").substr(2,8).

The assembly:

  • The GUID is in the following format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX.
  • I divided the GUID into 4 pieces, each piece divided into 2 types (or formats): XXXXXXXX and -XXXX-XXXX.
  • Now I'm building the GUID using these 2 types to assemble the GUID with call 4 pieces, as follows: XXXXXXXX -XXXX-XXXX -XXXX-XXXX XXXXXXXX.
  • To differ between these two types, I added a flag parameter to a pair creator function _p8(s), the s parameter tells the function whether to add dashes or not.
  • Eventually we build the GUID with the following chaining: _p8() + _p8(true) + _p8(true) + _p8(), and return it.

Link to this post on my blog

Enjoy! :-)


For my use-case, I required id generation that was guaranteed to be unique globally; without exception. I struggled with the problem for a while, and came up with a solution called tuid (Truly Unique ID). It generates an id with the first 32 characters being system-generated and the remaining digits representing milliseconds since epoch. In situations where I need to generate id's on client-side javascript, it works well. Have a look:

https://github.com/mongoh/tuid


let uniqueId = Date.now().toString(36) + Math.random().toString(36).substring(2);

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

If ID's are generated more than 1 millisecond apart, they are 100% unique.

If two ID's are generated at shorter intervals, and assuming that the random method is truly random, this would generate ID's that are 99.99999999999999% likely to be globally unique (collision in 1 of 10^15)

You can increase this number by adding more digits, but to generate 100% unique ID's you will need to use a global counter.

if you need RFC compatibility, this formatting will pass as a valid version 4 GUID:

let u = Date.now().toString(16) + Math.random().toString(16) + '0'.repeat(16);
let guid = [u.substr(0,8), u.substr(8,4), '4000-8' + u.substr(13,3), u.substr(16,12)].join('-');

_x000D_
_x000D_
let u = Date.now().toString(16)+Math.random().toString(16)+'0'.repeat(16);
let guid = [u.substr(0,8), u.substr(8,4), '4000-8' + u.substr(13,3), u.substr(16,12)].join('-');
document.getElementById("unique").innerHTML = guid;
_x000D_
<div id="unique">
</div>
_x000D_
_x000D_
_x000D_

Edit: The above code follow the intention, but not the letter of the RFC. Among other discrepancies it's a few random digits short. (Add more random digits if you need it) The upside is that this it's really fast :) You can test validity of your GUID here


I couldn't find any answer that uses a single 16-octet TypedArray and a DataView, so I think the following solution for generating a version 4 UUID per the RFC will stand on its own here:

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
}

I prefer it because it only relies on functions available to the standard ECMAScript platform.

Take note of the fact that at the time of writing this, getRandomValues is not something implemented for the crypto object in Node.js. However, it has the equivalent randomBytes function which may be used instead.


Just in case anyone dropping by google is seeking a small utility library, ShortId (https://www.npmjs.com/package/shortid) meets all the requirements of this question. It allows specifying allowed characters and length, and guarantees non-sequential, non-repeating strings.

To make this more of a real answer, the core of that library uses the following logic to produce its short ids:

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

I have not edited this to reflect only the most basic parts of this approach, so the above code includes some additional logic from the library. If you are curious about everything it is doing, take a look at the source: https://github.com/dylang/shortid/tree/master/lib


Here is a combination of the top voted answer, with a workaround for Chrome's collisions:

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

It is on jsbin if you want to test it.


Simple code that uses crypto.getRandomValues(a) on supported browsers (IE11+, iOS7+, FF21+, Chrome, Android Chrome). Avoids using Math.random() because that can cause collisions (for example 20 collisions for 4000 generated uuids in a real situation by 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);
}

Notes:

  • Optimised for code readability not speed, so suitable for say a few hundred uuid's per second. Generates about 10000 uuid() per second in Chromium on my laptop using http://jsbin.com/fuwigo/1 to measure performance.
  • Only uses 8 for "y" because that simplifies code readability (y is allowed to be 8, 9, A or B).

Hi here is an working example it generates 32-digit Unique 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)

Just thought I'd post yet another way of doing the same thing.

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

Don't use Math.random in anycase since it generated a non-cryptographic source of random numbers

Solution below using crypto.getRandomValues

function uuidv4() {
  return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
    // tslint:disable-next-line: no-bitwise
    const r =
      (window.crypto.getRandomValues(new Uint32Array(1))[0] *
        Math.pow(2, -32) * 16) |
      0;
    // tslint:disable-next-line: no-bitwise
    const v = c === "x" ? r : (r & 0x3) | 0x8;
    return v.toString(16);
  });
}

This link helps your to understand the Insecure Randomness thrown by Fortify Scanner


The UUID currently has a proposal for addition to the standard library and can be supported here https://github.com/tc39/proposal-uuid

The proposal encompasses having UUID as the following:

// We're not yet certain as to how the API will be accessed (whether it's in the global, or a
// future built-in module), and this will be part of the investigative process as we continue
// working on the proposal.
uuid(); // "52e6953d-edbe-4953-be2e-65ed3836b2f0"

This implemtation follows the same layout as the V4 random uuid generation found here: https://www.npmjs.com/package/uuid

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

I think it's noteworthy to understand how much bandwidth could be saved by this having an official implementation in the standard library. The authors of the proposal have also noted:

The 12 kb uuid module is downloaded from npm > 62,000,000 times a month (June 2019); making it available in the standard library eventually saves TBs of bandwidth globally. If we continue to address user needs, such as uuid, with the standard library, bandwidth savings add up.


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

This version is based on Briguy37's answer and some bitwise operators to extract nibble sized windows from the buffer.

It should adhere to the RFC Type 4 (random) schema, since I had problems last time parsing non-compliant UUIDs with Java's UUID.


I adjusted my own UUID/GUID generator with some extras here.

I'm using the following Kybos random number generator to be a bit more cryptographically sound.

Below is my script with the Mash and Kybos methods from baagoe.com excluded.

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

A simple solution to generate unique identification is to use time token and add random number to it. I prefer to prefix it with "uuid-".

Below function will generate random string of type: uuid-14d93eb1b9b4533e6. One doesn't need to generate 32 chars random string. 16 char random string is more than sufficient in this case to provide the unique UUIDs in javascript.

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

ES6 sample

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

Because i can, i thought i should share my solution, since it is a very fascinating problem and it has so many solutions.

It works for nodejs too, if you replace let buffer = new Uint8Array(); crypto.getRandomValues with let buffer = crypto.randomBytes(16)

I hope it helps somebody. It should beat most regex solutions in performance.

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

Performance charts, everybody loves them: jsbench

Have fun and thank you for all the other solutions, some served my quite long.


For those who are using Javascript on Windows (e.g. WScript / CScript / MSHTA). One can use ActiveX. Specifically, the Scriptlet.Typelib object:

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

Note that this answer only works on the technologies I listed, it will not work any browser, not even Microsoft Edge! So, your mileage will vary with this answer.


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

Old question, so this might never float to the top, but I've built on everything mentioned here to produce something twice as fast, portable all environments, including node, and upgraded from Math.random() to crypto-strength randomness. You might not think uuid needs crypto strength, but what that means is even less chance of a collision, which is the entire point of a uuid.

function random() {
    const
        fourBytesOn = 0xffffffff, // 4 bytes, all 32 bits on: 4294967295
        c = typeof crypto === "object"
            ? crypto // node or most browsers
            : typeof msCrypto === "object" // stinky non-standard IE
                ? 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
                : 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 4 32-bit (4-byte) random values
    // use crypto-grade randomness when available, else Math.random()
    const
        c = typeof crypto === "object"
            ? crypto // node or most browsers
            : typeof msCrypto === "object" // stinky non-standard IE
                ? 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
                : 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 */
}

Based on the work of broofa, I've added some more randomness by adding the timestamp to math.random()

Hope it might help

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

I'm using this below function, hope it may be useful.

    function NewGuid()
         {
           var sGuid="";
           for (var i=0; i<32; i++)
            {
              sGuid+=Math.floor(Math.random()*0xF).toString(0xF);
            }
           return sGuid;
         }

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

I really like how clean Broofa's answer is, but it's unfortunate that poor implementations of Math.random leave the chance for collision.

Here's a similar RFC4122 version 4 compliant solution that solves that issue by offsetting the first 13 hex numbers by a hex portion of the timestamp, and once depleted offsets by a hex portion of the microseconds since pageload. That way, even if Math.random is on the same seed, both clients would have to generate the UUID the exact same number of microseconds since pageload (if high-perfomance time is supported) AND at the exact same millisecond (or 10,000+ years later) to get the same UUID:

_x000D_
_x000D_
function generateUUID() { // Public Domain/MIT_x000D_
    var d = new Date().getTime();//Timestamp_x000D_
    var d2 = (performance && performance.now && (performance.now()*1000)) || 0;//Time in microseconds since page-load or 0 if unsupported_x000D_
    return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) {_x000D_
        var r = Math.random() * 16;//random number between 0 and 16_x000D_
        if(d > 0){//Use timestamp until depleted_x000D_
            r = (d + r)%16 | 0;_x000D_
            d = Math.floor(d/16);_x000D_
        } else {//Use microseconds since page-load if supported_x000D_
            r = (d2 + r)%16 | 0;_x000D_
            d2 = Math.floor(d2/16);_x000D_
        }_x000D_
        return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);_x000D_
    });_x000D_
}_x000D_
_x000D_
console.log(generateUUID())
_x000D_
_x000D_
_x000D_


Here's a fiddle to test.


This may be of use to someone...

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/


There are many correct answers here, but sadly, included code samples are quite cryptic and difficult to understand. This is how I create version 4 (random) UUIDs.

Note that following pieces of code make use of binary literals for improved readability, thus require ECMAScript 6.

Node version

function uuid4() {
  let array = new Uint8Array(16)
  crypto.randomFillSync(array)

  // manipulate 9th byte
  array[8] &= 0b00111111 // clear first two bits
  array[8] |= 0b10000000 // set first two bits to 10

  // manipulate 7th byte
  array[6] &= 0b00001111 // clear first four bits
  array[6] |= 0b01000000 // set first four bits to 0100

  const pattern = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  let idx = 0

  return pattern.replace(
    /XX/g,
    () => array[idx++].toString(16).padStart(2, "0"), // padStart ensures leading zero, if needed
  )
}

Browser version

Only the 2nd line is different.

function uuid4() {
  let array = new Uint8Array(16)
  crypto.getRandomValues(array)

  // manipulate 9th byte
  array[8] &= 0b00111111 // clear first two bits
  array[8] |= 0b10000000 // set first two bits to 10

  // manipulate 7th byte
  array[6] &= 0b00001111 // clear first four bits
  array[6] |= 0b01000000 // set first four bits to 0100

  const pattern = "XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX"
  let idx = 0

  return pattern.replace(
    /XX/g,
    () => array[idx++].toString(16).padStart(2, "0"), // padStart ensures leading zero, if needed
  )
}

Tests

And finally, corresponding tests (Jasmine).

describe(".uuid4()", function() {
  it("returns a UUIDv4 string", function() {
    const uuidPattern = "XXXXXXXX-XXXX-4XXX-YXXX-XXXXXXXXXXXX"
    const uuidPatternRx = new RegExp(uuidPattern.
      replaceAll("X", "[0-9a-f]").
      replaceAll("Y", "[89ab]"))

    for (let attempt = 0; attempt < 1000; attempt++) {
      let retval = uuid4()
      expect(retval.length).toEqual(36)
      expect(retval).toMatch(uuidPatternRx)
    }
  })
})

UUID v4 explained

A very good explanation of UUID version 4 is here: https://www.cryptosys.net/pki/uuid-rfc4122.html.

Final notes

Also, there are plenty of third-party packages. However, as long as you have just basic needs, I don't recommend them. Really, there is not much to win and pretty much to lose. Authors may pursue for tiniest bits of performance, "fix" things which aren't supposed to be fixed, and when it comes to security, it is a risky idea. Similarly, they may introduce other bugs or incompatibilities. Careful updates require time.


One line solution using Blobs.

window.URL.createObjectURL(new Blob([])).substring(31);

The value at the end (31) depends on the length of the URL.


Here is a totally non-compliant but very performant implementation to generate an ASCII-safe GUID-like unique identifier.

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

Generates 26 [a-z0-9] characters, yielding a UID that is both shorter and more unique than RFC compliant GUIDs. Dashes can be trivially added if human-readability matters.

Here are usage examples and timings for this function and several of this question's other answers. The timing was performed under Chrome m25, 10 million iterations each.

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

Here is the timing code.

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