5272

How do I create GUIDs (globally-unique identifiers) in JavaScript? The GUID / UUID should be at least 32 characters and should stay in the ASCII range to avoid trouble when passing them around.

I'm not sure what routines are available on all browsers, how "random" and seeded the built-in random number generator is, etc.

Mateen Ulhaq
  • 24,552
  • 19
  • 101
  • 135
Jason Cohen
  • 81,399
  • 26
  • 107
  • 114
  • 36
    GUIDs when repesented as as strings are at least 36 and no more than 38 characters in length and match the pattern ^\{?[a-zA-Z0-9]{36}?\}$ and hence are always ascii. – AnthonyWJones Sep 19 '08 at 20:35
  • 5
    David Bau provides a much better, seedable random number generator at http://davidbau.com/archives/2010/01/30/random_seeds_coded_hints_and_quintillions.html I wrote up a slightly different approach to generating UUIDs at http://blogs.cozi.com/tech/2010/04/generating-uuids-in-javascript.html – George V. Reilly May 04 '10 at 23:09
  • 1
    Weird that no one has mentioned this yet but for completeness, there's a plethora of [guid generators on npm](https://npmjs.org/search?q=guid) I'm willing to bet most of them work in browser too. – George Mauer Feb 03 '14 at 15:54
  • 1
    If anyone wants more options like different versions of the uuid and non standard guid support, REST based uuid generation services like these [https://fungenerators.com/api/uuid/ ] are an attractive option too. – dors Dec 15 '20 at 16:20
  • 2
    Some 12 years later with `BigInt` and ES6 classes, other techniques that yield rates of 500,000 uuid/sec can be done. [See reference](https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid/65500983#answer-65500983) – smallscript Dec 30 '20 at 06:34
  • 5
    As [others](https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid/62359248#62359248) [have](https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid/66332305#66332305) [mentioned](https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid/68990167#68990167), if you're only generating a small number of uuids in a browser, just use `URL.createObjectURL(new Blob()).substr(-36)`. ([Excellent browser support, too](https://caniuse.com/?search=createObjectURL)). (To avoid memory leakage, [call URL.revokeObjectURL(url)](https://stackoverflow.com/a/62359248/114558)) – rinogo Oct 21 '21 at 02:47
  • 1
    if you have mission-critical issue, better to write an endpoint which is written with pyhton and call it. Because its implemented such as described at https://datatracker.ietf.org/doc/html/rfc4122.html – Burcin Sep 15 '22 at 18:46

73 Answers73

5475

[Edited 2023-03-05 to reflect latest best-practices for producing RFC4122-compliant UUIDs]

crypto.randomUUID() is now standard on all modern browsers and JS runtimes. However, because new browser APIs are restricted to secure contexts, this method is only available to pages served locally (localhost or 127.0.0.1) or over HTTPS.

For readers interested in other UUID versions, generating UUIDs on legacy platforms or in non-secure contexts, there is the uuid module. It is well-tested and supported.

Failing the above, there is this method (based on the original answer to this question):

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

Note: The use of any UUID generator that relies on Math.random() is strongly discouraged (including snippets featured in previous versions of this answer) for reasons best explained here. TL;DR: solutions based on Math.random() do not provide good uniqueness guarantees.

broofa
  • 37,461
  • 11
  • 73
  • 73
  • 175
    Surely the answer to @Muxa's question is 'no'? It's never truly safe to trust something that came from the client. I guess it depends on how likely your users are to bring up a javascript console and manually change the variable so to something they want. Or they could just POST you back the id that they want. It would also depend on whether the user picking their own ID is going to cause vulnerabilities. Either way, if it's a random number ID that's going into a table, I would probably be generating it server-side, so that I know I have control over the process. – Cam Jackson Nov 01 '12 at 14:34
  • 49
    @DrewNoakes - UUIDs aren't just a string of completely random #'s. The "4" is the uuid version (4 = "random"). The "y" marks where the uuid variant (field layout, basically) needs to be embedded. See sections 4.1.1 and 4.1.3 of http://www.ietf.org/rfc/rfc4122.txt for more info. – broofa Nov 27 '12 at 22:13
  • 21
    im a bit confused, in javascript ```[1e7]+-1e3``` does not really mean anything, an array is added to a number? what am I missing? note: in typescript it does not pass – Ayyash Oct 20 '21 at 12:14
  • 1
    @Ayyash In my Chrome F12 console `[1e7]+-1e3` evaluates to a string: '10000000-1000' – manuell Oct 25 '21 at 17:04
  • 5
    @Ayyash see https://www.destroyallsoftware.com/talks/wat – manuell Oct 25 '21 at 17:11
  • 1
    @ayyash The original derivation of that code snippet can be found here: https://gist.github.com/jed/982883 . It is, admittedly, ludicrously cryptic. For something less cryptic: https://gist.github.com/jed/982883#gistcomment-2403369 – broofa Oct 26 '21 at 18:37
  • 4
    Very new browsers required for crypto.randomUUID(). https://caniuse.com/mdn-api_crypto_randomuuid. – wazz Nov 12 '21 at 18:02
  • @Ayyash this seems to produce the same result with valid JS/TS: `1e7 + '-' + 1e3` – Roope Hakulinen Feb 21 '22 at 15:46
  • 3
    This doesn't work in Typescript it says can't add `number[] and number` – dota2pro Apr 06 '22 at 12:09
  • nodejs/React gives the warning: `Use parentheses to clarify the intended order of operations: no-mixed-operators`; great solution though. – PLG May 10 '22 at 12:06
  • 12
    Typescript users: you can add `` right before the first array, like this: `[1e7]` - quick way to get it to pass. – NickyTheWrench May 25 '22 at 03:39
  • 5
    I like the custom solution, except for the expression `[1e7]+-1e3+-4e3+-8e3+-1e11` in it. I personally prefer the expression `\`${1e7}-${1e3}-${4e3}-${8e3}-${1e11}\`` instead. It's somewhat longer, but also somewhat clearer to me. And it allows me to easily change the generated UUID's format as well. – Bart Hofland Jul 12 '22 at 11:19
  • A big warning from me about `crypto.randomUUID()`: **it is only available in 'secure contexts'**. As far as I can tell, that means you can't use it if your site is HTTP, not HTTPS, or if you're (more likely) testing locally with HTTP. An absurd decision IMHO considering UUIDs are used for all sorts of purposes, many of them not remotely security-sensitive. I'll be forced to use the NPM module. – Jez Nov 15 '22 at 22:49
  • For those who want to use `crypto.randomUUID()` by just running locally in a simple script file with Node.js, you'll need to import with `crypto = require("crypto");` – Samuel T. Aug 03 '23 at 18:35
2623

UUIDs (Universally Unique IDentifier), also known as GUIDs (Globally Unique IDentifier), according to RFC 4122, are identifiers designed to provide certain uniqueness guarantees.

While it is possible to implement RFC-compliant UUIDs in a few lines of JavaScript code (e.g., see @broofa's answer, below) there are several common pitfalls:

  • Invalid id format (UUIDs must be of the form "xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx", where x is one of [0-9, a-f] M is one of [1-5], and N is [8, 9, a, or b]
  • Use of a low-quality source of randomness (such as Math.random)

Thus, developers writing code for production environments are encouraged to use a rigorous, well-maintained implementation such as the uuid module.

Saiansh Singh
  • 583
  • 5
  • 16
John Millikin
  • 197,344
  • 39
  • 212
  • 226
  • 211
    Actually, the RFC allows for UUIDs that are created from random numbers. You just have to twiddle a couple of bits to identify it as such. See section 4.4. Algorithms for Creating a UUID from Truly Random or Pseudo-Random Numbers: http://www.rfc-archive.org/getrfc.php?rfc=4122 – Jason DeFontes Sep 19 '08 at 20:28
  • 69
    This should not be the accepted answer. It does not actually answer the question - instead encouraging the import of 25,000 lines of code for something you can do with one line of code in any modern browser. – Abhi Beckert Jul 08 '20 at 00:36
  • 1
    @AbhiBeckert the answer is from 2008 and for node.js projects it might be valid to choose a dependency more over project size – Phil Sep 29 '20 at 13:48
  • 9
    @Phil this is a "highly active question", which means it should have an excellent answer with a green tick. Unfortunately that's not the case. There is nothing wrong or incorrect with this answer (if there was, I'd edit the answer) - but another far better answer exists below and I think it should be at the top of the list. Also the question is specifically relating to javascript in a browser, not node.js. – Abhi Beckert Oct 08 '20 at 03:47
  • 3
    I challenge the claim that Math.random is that low of a quality of randomness. https://v8.dev/blog/math-random. As you can see, it's passes a good test suite, and the same algorithm is used by v8, FF and Safari. And the RFC states, pseudo-random numbers are acceptable for UUIDs – Munawwar May 27 '21 at 08:38
  • I think this answer should be edited by a qualified mod. Not only is it factually wrong, but it also doesn't answer the question at hand. Javascript development is different in the context of browser vs server. It's not trivial when a question targets the browser. Might well be saying use a node.js package when a question is specifically about Edge or Opera. Also, it may be better to request a UUID over REST, although that's only opinion. This way various means can be used to ensure it is truly unique. The server can even use the suggested package. But most servers don't use node.js either. – JSON May 28 '22 at 04:11
  • Or even better use asm.js. if we're going to offer irrelevant answers we might as well go hard on it – JSON May 28 '22 at 04:20
  • I tend to agree with [Munawwar](https://stackoverflow.com/users/856465). What's in a UUID? Most of the time, I just want to get a value that is pretty unique. Using `Math.random` seems to suffice for me in practice. It would be interesting to learn about some practical reasons why `Math.random` should be avoided for daily non-critical use, and in which circumstances the use `Math.random` would yield problematic practical issues. I guess that's off-topic here. I will try to spend some time to dive deeper in this issue, but for now I am not (yet) convinced regarding the "`Math.random` ban". – Bart Hofland Jun 28 '22 at 08:44
  • @BartHofland @munawwar: The issue with Math.random() isn't that implementations are low-quality. It's that they are not guaranteed to be high-quality. Even modern implementations that rely on "good" PRNG algos such as `xorshift128+` (as most modern browsers now do) suffer from being deterministic. Anyone with knowledge of the internal state can predict what values will be generated. This can be exploited for malicious purposes. Hence, the recommendation for "cryptographic quality" RNGs that introduce real entropy into the RNG state generation algorithm. – broofa Jul 11 '22 at 19:04
  • @broofa: I understand the necessity of having a secure nondeterministic random number generator. However, I still fail to see why the use of a partially deterministic RNG can be a problem when generating UUIDs (especially if those UUIDs are only needed for internal purposes). I also fail to find information about the dangers of low-quality UUIDs and how such UUIDs can actually be exploited for malicious purposes. Can you please elaborate a little on this? Or provide an example? Or refer to an information source on the Internet that provides such explanations and/or examples? – Bart Hofland Jul 12 '22 at 10:28
  • @broofa: It seems that it all comes down to the consideration if the next generated UUID should be hard to predict. For most of my own purposes which just involves generating unique values for identifying objects, entities, components etc., that predictability does not seem to be that important. I do not use any of my generated UUIDs in the context of cryptographic functionality or any other contexts where true randomness is important. So mostly I do not consider the benefits of high-quality UUIDs to outweigh the overhead of (and the additional dependency on) yet another external library. – Bart Hofland Jul 12 '22 at 11:09
  • Now we have in [node.js](https://nodejs.org/api/crypto.html#cryptorandomuuidoptions) and in the [browser](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/randomUUID) `crypto.randomUUID()` no need for uuid packages anymore for most use cases. – Ciro Spaciari Oct 12 '22 at 12:38
  • @BartHofland It is extremely important for security. Predictable UUIDs have been exploited to gain unauthorized access to resources. e.g. predict a password reset token, or gain access to resources identified by secret UUID links. – Eric Elliott Feb 23 '23 at 01:38
987

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:

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

var onClick = function(){
    document.getElementById('uuid').textContent = generateUUID();
}
onClick();
#uuid { font-family: monospace; font-size: 1.5em; }
<p id="uuid"></p>
<button id="generateUUID" onclick="onClick();">Generate UUID</button>

Here's a fiddle to test.


Modernized snippet for ES6

const generateUUID = () => {
  let
    d = new Date().getTime(),
    d2 = ((typeof performance !== 'undefined') && performance.now && (performance.now() * 1000)) || 0;
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, c => {
    let r = Math.random() * 16;
    if (d > 0) {
      r = (d + r) % 16 | 0;
      d = Math.floor(d / 16);
    } else {
      r = (d2 + r) % 16 | 0;
      d2 = Math.floor(d2 / 16);
    }
    return (c == 'x' ? r : (r & 0x7 | 0x8)).toString(16);
  });
};

const onClick = (e) => document.getElementById('uuid').textContent = generateUUID();

document.getElementById('generateUUID').addEventListener('click', onClick);

onClick();
#uuid { font-family: monospace; font-size: 1.5em; }
<p id="uuid"></p>
<button id="generateUUID">Generate UUID</button>
José Cabo
  • 6,149
  • 3
  • 28
  • 39
Briguy37
  • 8,342
  • 3
  • 33
  • 53
  • 38
    Bear in mind, `new Date().getTime()` is not updated every millisecond. I'm not sure how this affects the expected randomness of your algorithm. – devios1 Mar 18 '12 at 17:27
  • 95
    [performance.now](https://github.com/daniellmb/perfnow.js) would be even better. Unlike Date.now, the timestamps returned by `performance.now()` are not limited to one-millisecond resolution. Instead, they represent times as floating-point numbers with up to **microsecond precision**. Also unlike Date.now, the values returned by performance.now() **always increase at a constant rate**, independent of the system clock which might be adjusted manually or skewed by software such as the Network Time Protocol. – SavoryBytes Mar 13 '14 at 04:25
  • The actual time resolution may or may not be 17 ms (1/60 second), not 1 ms. – Peter Mortensen Dec 30 '20 at 03:28
  • Would [Crypto.getRandomValues](https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues) fix the main problems with Math.random?? – John Apr 01 '21 at 22:07
  • Note: Zak had made an update to add the following. `const { performance } = require('perf_hooks');` to define the `performance` variable. Thus for node.js strict implementations this may be needed. However, this has been removed from the answer because it broke the snippet and will not work with JavaScript used in most other environments, e.g. in browsers. – Briguy37 Apr 08 '21 at 20:23
  • i am new to javascript. when I run the ES6 version with node 14, i get `ReferenceError: performance is not defined`. How do i fix it? – Naveen Reddy Marthala Sep 11 '21 at 08:41
  • 3
    @NaveenReddyMarthala Node.js by default runs JavaScript in strict mode, which unfortunately doesn't allow boolean logic operators to shorthand check the truthiness of `undefined` variables. To fix this, try replacing `var d2 = (performance ..` with `var d2 = (typeof performance !== 'undefined' ..` as in the update version. The other option (which will actually utilize the enhanced precision of performance with Node.js rather than throwing it away) is to re-add `const { performance } = require('perf_hooks');` in your requirements. – Briguy37 Sep 13 '21 at 14:47
  • I've added the `typeof performance !== 'undefined'` in the updated ES6 snippet because the code wasn't doing what was intended. The old code would have produced a crash if the `performance` variable wasn't declare instead of defaulting to `0` as expected. CC: @Briguy37 – José Cabo Jan 21 '23 at 19:08
  • Why the first code snippet uses `(c === 'x' ? r : (r & 0x3 | 0x8))` while the "modernized" ES6 uses `(c == 'x' ? r : (r & 0x7 | 0x8))`. I.e. Why `0x3` vs `0x7`. That'd result in different values. Does anybody know why? Also, the only difference between the normal one and the "modernized" one are the fat-arrow functions, the use of let instead of var and the bit I've mentioned before. The ES6 one shouldn't be used IMO unless clarified by somebody. – José Cabo Jan 21 '23 at 19:15
  • @JoséCabo: That is from 4.4 of https://www.ietf.org/rfc/rfc4122.txt: "Set the two most significant bits (bits 6 and 7) of the clock_seq_hi_and_reserved to zero and one, respectively". 0x3 is 0011 in binary, so binary AND with that sets the two most significant bits to zero, and then binary ORing with 0x8 (1000 in binary) sets the MSB to 1 as specified. – Briguy37 Jan 24 '23 at 14:39
  • The modernized ES6 snippet generates non-V4 UUIDs, specifically the regex `^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$` does not match, at the position where `[89ab]` is expected. – Alex Suzuki Apr 19 '23 at 06:23
544

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 four bits of the result and wasting the rest), you may start to wonder about performance. Indeed, joelpt even decided to toss out an 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 12 times, the accepted answer by over 9 times, and the fast-non-compliant answer by 2-3 times. And I'm still RFC 4122 compliant.

Interested in how? I've put the full source on http://jsfiddle.net/jcward/7hyaC/3/ and on https://jsben.ch/xczxS

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

function broofa() {
    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(broofa())

So it replaces x with any random hexadecimal digit, y with random data (except forcing the top two 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:

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

console.log(e1())

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:

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

console.log(e2())

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:

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

console.log(e4())

The next optimization is another classic. Since we're only handling four bits of output in each loop iteration, let's cut the number of loops in half and process eight bits in 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.

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

console.log(e5())

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 reassigning, 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:

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

console.log(e7())

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.

EscapeNetscape
  • 2,892
  • 1
  • 33
  • 32
Jeff Ward
  • 16,563
  • 6
  • 48
  • 57
  • 26
    This code still contains a couple of errors: the `Math.random()*0xFFFFFFFF` lines should be `Math.random()*0x100000000` for full randomness, and `>>>0` should be used instead of `|0` to keep the values unsigned (though with the current code I think it gets away OK even though they are signed). Finally it would be a very good idea these days to use `window.crypto.getRandomValues` if available, and fall-back to Math.random only if absolutely necessary. Math.random may well have less than 128 bits of entropy, in which case this would be more vulnerable to collisions than necessary. – Dave Jul 18 '15 at 17:55
  • 17
    Can I just say -- I cannot count how many times I've pointed devs to this answer because it so beautifully points out the tradeoffs between performance, code-elegance, and readability. Thank you Jeff. – Nemesarial Nov 06 '20 at 14:07
  • I don't know if @Broofa's answer has changed since these tests were run (or if the browser engines running the tests have changed - it has been five years), but I just ran them both on two different benchmarking services (jsben.ch and jsbench.github.io), and in each case Broofa's answer (using Math.random) was faster than this e7() version by 30 - 35%. – Andrew Nov 17 '20 at 21:24
  • @Andy is right. Broofa's code is faster as of Aug 2021. I implemented Dave's suggestions and ran the test myself. But I don't imagine the difference should matter all that much in production: https://jsbench.github.io/#80610cde9bc93d0f3068e5793e60ff11 – Doomd Aug 12 '21 at 22:38
  • I feel your comparisons may be unfair as broofa's anwer appears to be for an e4 UUID, and your testing against Ward's e7 implementation here. When you compare broofa's answer to the e4 version presented to here, this answer is faster. – bedalton Aug 20 '21 at 14:11
  • 1
    @bedalton: Why would we compare broofa's answer to "the e4 version"? The "4" in e4 simply refers to the iteration of optimization and not to the version of UUID, right? – rinogo Oct 21 '21 at 02:05
  • I did not catch that – bedalton Oct 26 '21 at 15:30
  • @Andrew you have to notice that you generate LUT every time function is called, and in e7 example it happens only once, so after I created a LUT manually (it fetched through) e7 beats broofa – Artur Papikian Sep 28 '22 at 08:47
221

Use:

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

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

If IDs are generated more than 1 millisecond apart, they are 100% unique.

If two IDs are generated at shorter intervals, and assuming that the random method is truly random, this would generate IDs 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 IDs 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('-');

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;
<div id="unique">
</div>

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 is really fast :) You can test validity of your GUID here

Doomd
  • 1,271
  • 1
  • 16
  • 27
Simon Rigét
  • 2,757
  • 5
  • 30
  • 33
  • 9
    This is not UUID though? – Marco Kerwitz Dec 26 '17 at 23:28
  • No. UUID/GUID's is a 122 bit (+ six reserved bits) number. it might guarantee uniqueness through a global counter service, but often it relays on time, MAC address and randomness. UUID's are not random! The UID I suggest here is not fully compressed. You could compress it, to a 122 bit integer, add the 6 predefined bits and extra random bits (remove a few timer bits) and you end up with a perfectly formed UUID/GUID, that you would then have to convert to hex. To me that doesn't really add anything other than compliance to the length of the ID. – Simon Rigét Feb 18 '18 at 00:05
  • 12
    Relaying on MAC addresses for uniqueness on virtual machines is a bad idea! – Simon Rigét Feb 18 '18 at 00:48
  • 1
    I do something like this, but with leading characters and some dashes (e.g `[slug, date, random].join("_")` to create `usr_1dcn27itd_hj6onj6phr`. It makes it so the id also doubles as a "created at" field – Seph Reed Jun 06 '19 at 19:23
  • 1
    Building on @SephReed's comment, I think having the date part first is nice since it sorts chronologically, which may provide benefits later if storing or indexing the IDs. – totalhack Oct 14 '20 at 20:15
  • 1
    For those wondering: `toString(36)` converts in a base-36 numeration (0..9a..z). Example: `(35).toString(36)` is `z`. – Basj Dec 15 '20 at 08:57
  • Not compatible with IE since .repeat method is [not available](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/repeat). – FatalError Jul 27 '21 at 08:20
  • Changing _'0'.repeat(16)_ to _'000000'_ worked for me. I don't know why 0 needs to be repeated 16 times, only couple of times should be enough. – FatalError Jul 27 '21 at 08:41
  • The the many zeros in front are needed, because a random number might be just one digit. Even if its very rare, it still has to work. – Simon Rigét Jul 31 '21 at 22:13
191

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;
}
Kevin Hakanson
  • 41,386
  • 23
  • 126
  • 155
  • 6
    You should declare the array size beforehand rather than sizing it dynamically as you build the GUID. `var s = new Array(36);` – MgSam Mar 25 '13 at 20:03
  • 2
    I think there's a very minor bug in the line that sets bits bits 6-7 of the clock_seq_hi_and_reserved to 01. Since s[19] is a character '0'..'f' and not an int 0x0..0xf, (s[19] & 0x3) | 0x8 will not be randomly distributed -- it will tend to produce more '9's and fewer 'b's. This only makes a difference if you care about the random distribution for some reason. – John Velonis Apr 18 '13 at 15:35
105

This is the fastest GUID-like string generator method in the format XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX. It does not generate a 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 (third 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 four pieces, each piece divided into two types (or formats): XXXXXXXX and -XXXX-XXXX.
  • Now I'm building the GUID using these two types to assemble the GUID with call four 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! :-)

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Slavik Meltser
  • 9,712
  • 3
  • 47
  • 48
  • 17
    This implementation is incorrect. Certain characters of the GUID require special treatment (e.g. the 13th digit needs to be the number 4). – JLRishe Nov 12 '13 at 08:12
  • Slightly rewritten, with fat arrow functions and toStr(depricated) -> toString. Also removed the hyphens! guid = () => { _p8 = () => {return (Math.random() * 10000000000).toString(16).substr(0,8);} return `${_p8()}${_p8()}${_p8()}${_p8()}`; }; – Peter Korinek TellusTalk Aug 15 '22 at 12:12
84

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');
joelpt
  • 4,675
  • 2
  • 29
  • 28
75

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Prestaul
  • 83,552
  • 10
  • 84
  • 84
  • 10
    Note that this isn't a GUID in the technical sense, because it does nothing to guarantee uniqueness. That may or may not matter depending on your application. – Stephen Deken Sep 19 '08 at 20:07
  • 3
    A quick note about performance. This solution creates 36 strings total to get a single result. If performance is critical, consider creating an array and joining as recommended by: http://tinyurl.com/y37xtx Further research indicates it may not matter, so YMMV: http://tinyurl.com/3l7945 – Brandon DuRette Sep 22 '08 at 18:14
  • 2
    Regarding uniqueness, it's worth noting that version 1,3, and 5 UUIDs are deterministic in ways version 4 isn't. If the inputs to these uuid generators - node id in v1, namespace and name in v3 and v5 - are unique (as they're supposed to be), then the resulting UUIDs be unique. In theory, anyway. – broofa Jun 29 '17 at 13:26
  • These GUIDs are invalid because they don't specify version and variant required by the ITU-T | ISO recommendation. – Daniel Marschall Dec 12 '21 at 01:42
  • @DanielMarschall, this doesn't produce UUIDs, but does produce valid GUIDs which were common place in Microsoft code (e.g. .Net) in 2008 when this answer was written. Note, that this is also why the hex characters are forced to upper case. See: https://learn.microsoft.com/en-us/windows/win32/msi/guid – Prestaul Dec 13 '21 at 16:51
  • @Prestaul I understand that GUID is an implementation of UUID. I am not aware that GUIDs don't follow the rules of the ITU-T, which say that random GUIDs ("version 4") need the "version" field set to 4 and the variant bits set to 0b01. Of course they are "valid" in regards syntax. But it is not correct to produce GUIDs which do not follow the specifications (i.e. produce a random GUID but label it as time based would cause invalid metadata about the GUID). – Daniel Marschall Dec 13 '21 at 17:54
  • @DanielMarschall You are correct that this doesn't follow the UUID/GUID specs. I'm simply stating that, in 2008 when this was written, GUID and UUID did not mean the same thing and Microsoft had its own definition and implementation of GUIDs which was in quite common use. That definition (did you see the link I shared) does not have a version/variant in it. – Prestaul Dec 14 '21 at 18:33
  • FWIW, this answer was edited early on to recommend using one of the better solutions but that recommendation was removed later by the community. – Prestaul Dec 14 '21 at 18:36
69

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ripper234
  • 222,824
  • 274
  • 634
  • 905
  • 3
    note that the first version, the one ` window.crypto.getRandomValues`, does not keep the Version 4 UUIDs format defined by RFC 4122. That is instead of `xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx` it yields `xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`. – humanityANDpeace Sep 03 '16 at 07:58
65

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
      )
}
Community
  • 1
  • 1
Jed Schmidt
  • 2,907
  • 23
  • 23
55

You can use node-uuid. It provides 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 a 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'

ECMAScript 2015 (ES6):

import uuid from 'uuid/v4';
const id = uuid();
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Kyros Koh
  • 188
  • 2
  • 12
  • 2
    **Note:** These imports didn't work for me. Import statements have changed, as stated in the repo: `const { v4: uuidv4 } = require('uuid');` and ES6: `import { v4 as uuidv4 } from 'uuid';` – vladsiv Dec 02 '20 at 00:09
45

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.


EDIT:

A more compact and universal solution, as suggested by rinogo:

URL.createObjectURL(new Blob([])).slice(-36);
Ostap Brehin
  • 3,240
  • 3
  • 25
  • 28
Tikolu
  • 193
  • 2
  • 12
  • 13
    Alternatively `window.URL.createObjectURL(new Blob([])).split('/').pop()` will do the same without having to rely on external factors like URL length. – wafs Mar 08 '21 at 03:57
  • 2
    What is "Blob"/"Blobs"? – Peter Mortensen Apr 02 '21 at 18:33
  • @PeterMortensen A blob is an opaque, efficient representation of some amount of "raw" (binary) data, for convenience of scripting on the Web. – Armen Michaeli Aug 23 '21 at 17:39
  • 1
    Umm this most definitely does not work. To work reliably on different domains, it needs to be changed to something like `window.URL.createObjectURL(new Blob([])).substr(-36)` – rinogo Oct 21 '21 at 02:32
  • 1
    What's the drawback of this solution? – Charaf Mar 13 '22 at 00:46
  • @Charaf Doesn't seem to have many drawbacks except for no support on Internet Explorer – Tikolu Mar 14 '22 at 01:07
  • On Safari 15.3 you will get: "ikdev.com/98455e8b-7f1c-44b3-8424-91e06214cb50", so this is not good solution. – lissajous Apr 08 '22 at 12:04
  • 1
    FYI there's some concern and advice given about memory management highlighted on MDN. https://developer.mozilla.org/en-US/docs/Web/API/URL/createObjectURL#memory_management – Lucas Apr 28 '22 at 14:14
  • 1
    instead of `substr` which is deprecated now, the `slice` might be used – asduj Apr 29 '22 at 12:09
  • since `substr` is depricated we can also use match `const [uuid] = URL.createObjectURL(new Blob([])).match(/[a-z0-9-]+$/)` – bert84 Sep 14 '22 at 10:24
  • 2
    Better to replace substr with slice in the compact solution. `URL.createObjectURL(new Blob([])).slice(-36)` – lk404 Dec 21 '22 at 05:09
38

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mathieu Pagé
  • 10,764
  • 13
  • 48
  • 71
38
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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
sleeplessnerd
  • 21,853
  • 1
  • 25
  • 29
34

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

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);
    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('1. New Guid:   ' + Guid.newGuid());

// DEMO: Show empty GUID
console.log('2. Empty Guid: ' + Guid.empty);

Usage:

Guid.newGuid()

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

Guid.empty

"00000000-0000-0000-0000-000000000000"

Matt
  • 25,467
  • 18
  • 120
  • 187
kayz1
  • 7,260
  • 3
  • 53
  • 56
  • 1
    What is bothering about *all* answers is that it seems _ok_ for JavaScript to store the `GUID` as a `string`. Your answer at least tackles the *much* more efficient storage using a `Uint16Array`. The `toString` function should be using the binary representation in an JavaScript `object` – Sebastian May 04 '14 at 11:03
  • This UUIDs produced by this code are either weak-but-RFC-compliant (_guid), or strong-but-not-RFC-compliant (_cryptoGuid). The former uses Math.random(), which is now known to be a poor RNG. The latter is failing to set the version and variant fields. – broofa Jun 29 '17 at 13:37
  • @broofa - What would you suggest to make it strong **and** RFC-compliant? And why is _cryptoGuid not RFC-compliant? – Matt Mar 15 '18 at 09:57
  • @Matt _cryptoGuid() sets all 128 bits randomly, meaning it doesn't set the version and variant fields as described in the RFC. See my alternate implementation of uuidv4() that uses crypto.getRandomValues() in my top-voted answer, above, for a strong+compliant implementation. – broofa Mar 16 '18 at 17:13
28

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 <baagoe@baagoe.com>, 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 <baagoe@baagoe.com>, 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);
  });
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jerod Venema
  • 44,124
  • 5
  • 66
  • 109
27

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.

Wojciech Bednarski
  • 6,033
  • 9
  • 49
  • 73
23
  // 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('-');
jablko
  • 71
  • 1
  • 2
23

Added in: v15.6.0, v14.17.0 there is a built-in crypto.randomUUID() function.

import * as crypto from "crypto";

const uuid = crypto.randomUUID();

In the browser, crypto.randomUUID() is currently supported in Chromium 92+ and Firefox 95+.

Dan Atkinson
  • 11,391
  • 14
  • 81
  • 114
Pier-Luc Gendreau
  • 13,553
  • 4
  • 58
  • 69
17

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

var rand = Math.random;

function UUID() {
    var nbr, randStr = "";
    do {
        randStr += (nbr = rand()).toString(16).substr(3, 6);
    } while (randStr.length < 30);
    return (
        randStr.substr(0, 8) + "-" +
        randStr.substr(8, 4) + "-4" +
        randStr.substr(12, 3) + "-" +
        ((nbr*4|0)+8).toString(16) + // [89ab]
        randStr.substr(15, 3) + "-" +
        randStr.substr(18, 12)
    );
}

console.log( UUID() );

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
John Fowler
  • 3,173
  • 3
  • 18
  • 31
16

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);
        }
    );
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Andrew
  • 1,590
  • 4
  • 19
  • 25
15

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()}`;
}
Behnam
  • 6,244
  • 1
  • 39
  • 36
  • An explanation would be in order. E.g., what ES6 features does it use that previous answers don't? Please respond by [editing your answer](https://stackoverflow.com/posts/44996682/edit), not here in comments (***without*** "Edit:", "Update:", or similar - the answer should appear as if it was written today). – Peter Mortensen Apr 02 '21 at 17:28
15

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
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Aral Roca
  • 5,442
  • 8
  • 47
  • 78
  • works like a charm. Better than trying to generate manually. Very clever! – Paulo Henrique Queiroz Dec 11 '20 at 18:15
  • The performance is quite worst, but depending on the case it can be enough – Aral Roca Dec 15 '20 at 16:37
  • For the fastest combined generator that is compliant w/node-clock-seq, monotonic in time, etc. This forms a good basis to seed a `uuid4` generator w/60-bits of epoch70 μ-seconds of monotonic time, 4-bit uuid-version, and 48-bit node-id and 13-bit clock-seq with 3-bit uuid-variant. --
    Combining using `BigInt` to write `ntohl` and related conversion this works very fast with the [`lut` approach here](https://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid/21963136#comment-50951376). --
    I can provide code if desired.
    – smallscript Dec 29 '20 at 02:08
  • Is the inclusion of a UUID here guaranteed, or is it just something that the current browser implementations all happen to do? – M. Justin Jul 15 '21 at 20:10
  • 1
    @M.Justin It's guaranteed -- you can follow https://w3c.github.io/FileAPI/#dfn-createObjectURL to where it is specified, quoting, "Generate a UUID [RFC4122] as a string and append it to result". – Armen Michaeli Dec 28 '22 at 16:06
15

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 <baagoe@baagoe.com>, 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));
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Tracker1
  • 19,103
  • 12
  • 80
  • 106
14

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:

const 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 data = crypto.getRandomValues(new Uint8Array(16)); /// Fill the buffer with random data
    data[6] = (data[6] & 0xf) | 0x40; /// Patch the 6th byte to reflect a version 4 UUID
    data[8] = (data[8] & 0x3f) | 0x80; /// Patch the 8th byte to reflect a variant 1 UUID (version 4 UUIDs are)
    const view = new DataView(data.buffer); /// Create a view backed by a 16-byte buffer
    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, where possible -- which is all but one procedure
  • it only uses a single buffer, minimizing copying of data, which should in theory yield performance advantages

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.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
  • This is readable code, thank you. IMO the accepted answer has too complicated code, but this instead is understandable. – Ciantic Mar 17 '23 at 13:19
13

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}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Andrea Turri
  • 6,480
  • 7
  • 37
  • 63
13

The following is simple code that uses crypto.getRandomValues(a) on supported browsers (Internet Explorer 11+, iOS 7+, Firefox 21+, Chrome, and Android Chrome).

It 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 it is suitable for, say, a few hundred UUIDs per second. It generates about 10000 uuid() per second in Chromium on my laptop using http://jsbin.com/fuwigo/1 to measure performance.
  • It only uses 8 for "y" because that simplifies code readability (y is allowed to be 8, 9, A, or B).
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
robocat
  • 5,293
  • 48
  • 65
13

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jonathan Potter
  • 2,981
  • 1
  • 24
  • 19
  • BTW, why does it generate only numbers and not characters as well? much less secure – vsync Sep 30 '18 at 06:27
  • 2
    you can also add characters (letters ) like this: `Array.from((window.crypto || window.msCrypto).getRandomValues(new Uint32Array(4))).map(n => n.toString(16)).join('-')` – magikMaker Mar 29 '19 at 19:55
12

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), and 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;
};
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Anatoly Mironov
  • 7,356
  • 1
  • 26
  • 27
12

This one is based on date, and adds a random suffix to "ensure" uniqueness.

It works well for CSS identifiers, 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;
        };
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
ling
  • 9,545
  • 4
  • 52
  • 49
12

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, '-');
}
Mark Amery
  • 143,130
  • 81
  • 406
  • 459
ceving
  • 21,900
  • 13
  • 104
  • 178
  • 1
    Well most of the js devs are web developers, and we won't understand what bitwise operators do, because we don't use them most of the times we develop. Actually I never needed any of them, and I am a js dev since '97. So your example code is still totally unreadable to the average web developer who will read it. Not to mention that you still use single letter variable names, which makes it even more cryptic. Probably read Clean Code, maybe that helps: https://www.amazon.com/Clean-Code-Handbook-Software-Craftsmanship/dp/0132350882 – inf3rno Sep 22 '18 at 22:16
  • 1
    @inf3rno don't bash him, all the proposed solutions in this thread are cryptic but they are correct answers considering the question was to have a one-liner of sorts. that's what one-liners are cryptic. they can't afford to be readable to the average developer but they save screen real estate where a simple preceding comment will do. And as a result, ends up being much more readable that way then if it had been in "readable code" instead. – tatsu Dec 06 '19 at 15:19
  • @user1529413 Yes. Uniqueness requires an index. – ceving Feb 14 '20 at 09:37
  • This is my favourite answer, because it's building a UUID as a 16-byte (128 bit) value, and not its serialized, nice to read form. It'd be trivially easy to drop the string stuff and just set the correct bits of a random 128bit, which is all a uuidv4 needs to be. You could base64 it for shorter URLs, pass it back to some webassembly, store it in less memory space than as a string, make it a 4096-size buffer and put 256 uuids in it, store in a browser db, etc. Much better than having everything as a long, lowercase hex-encoded string from the start. – Josh from Qaribou Jun 03 '20 at 01:13
10

OK, using the uuid package, and its 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 information, visit the npm page here.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Alireza
  • 100,211
  • 27
  • 269
  • 172
10

Inspired by broofa's answer I had my own take on it:

Here's the cryptographically stronger version using crypto.getRandomValues.

function uuidv4() {
    const a = crypto.getRandomValues(new Uint16Array(8));
    let i = 0;
    return '00-0-4-1-000'.replace(/[^-]/g, 
            s => (a[i++] + s * 0x10000 >> s).toString(16).padStart(4, '0')
    );
}

console.log(uuidv4());

and here's the faster version using Math.random using almost the same principle:

function uuidv4() {
    return '00-0-4-1-000'.replace(/[^-]/g,
            s => ((Math.random() + ~~s) * 0x10000 >> s).toString(16).padStart(4, '0')
    );
}

console.log(uuidv4());
blubberdiblub
  • 4,085
  • 1
  • 28
  • 30
7

It is important to use well-tested code that is maintained by more than one contributor instead of whipping your own stuff for this.

This is one of the places where you probably want to prefer the most stable code than the 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 is Bower enabled so I can take updates easily.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Shital Shah
  • 63,284
  • 17
  • 238
  • 185
7

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
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
dgellow
  • 692
  • 1
  • 11
  • 18
  • This still gives an error Unexpected mix of '&' and '>>'. Use parentheses to clarify the intended order of operations. So perhaps: `return (c ^ crypto.getRandomValues(new Uint8Array(1))[0] & (15 >> c / 4)).toString(16);` is better – Willster Oct 13 '22 at 09:52
7

The most simple function to do this:

function createGuid(){  
   let S4 = () => Math.floor((1+Math.random())*0x10000).toString(16).substring(1); 
   let guid = `${S4()}${S4()}-${S4()}-${S4()}-${S4()}-${S4()}${S4()}${S4()}`;
   
   return guid.toLowerCase();  
}
Fernando Teles
  • 121
  • 2
  • 4
6

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

Example:

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

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

Example:

const uuidv4 = require('uuid/v4');
uuidv4(); // ⇨ '10ba038e-48da-487b-96e8-8d3b99b6d18a'
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
andersh
  • 8,105
  • 6
  • 39
  • 30
6

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.js version

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

  // Manipulate the 9th byte
  array[8] &= 0b00111111 // Clear the first two bits
  array[8] |= 0b10000000 // Set the first two bits to 10

  // Manipulate the 7th byte
  array[6] &= 0b00001111 // Clear the first four bits
  array[6] |= 0b01000000 // Set the 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 a leading zero, if needed
  )
}

Browser version

Only the second line is different.

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

  // Manipulate the 9th byte
  array[8] &= 0b00111111 // Clear the first two bits
  array[8] |= 0b10000000 // Set the first two bits to 10

  // Manipulate the 7th byte
  array[6] &= 0b00001111 // Clear the first four bits
  array[6] |= 0b01000000 // Set the 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 a 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: Generate a UUID compliant with RFC 4122.

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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
skalee
  • 12,331
  • 6
  • 55
  • 57
5

I'm using this below function:

function NewGuid()
{
    var sGuid = "";
    for (var i=0; i<32; i++)
    {
        sGuid += Math.floor(Math.random()*0xF).toString(0xF);
    }
    return sGuid;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Giridhar
  • 95
  • 2
  • 4
5

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

The below function will generate a random string of type: uuid-14d93eb1b9b4533e6. One doesn't need to generate a 32-characters random string. A 16-character 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));
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
mangalbhaskar
  • 71
  • 1
  • 3
5

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

It should beat most regular expression solutions in performance.

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

Performance charts (everybody loves them): jsbench

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
incureforce
  • 21
  • 1
  • 3
4

Just in case anyone dropping by Google is seeking a small utility library, 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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
MaxPRafferty
  • 4,819
  • 4
  • 32
  • 39
4

I found this script useful for creating GUIDs in JavaScript

https://github.com/addui/GUIDJS

var myGuid = GUID();
Dustin Poissant
  • 3,201
  • 1
  • 20
  • 32
  • This [uses `Math.random` under the hood](https://github.com/dustinpoissant/GUIDJS/blob/62c1dd3af36ea7e23194ac89386ca51ac2d4b541/src/GUID.js#L5). Therefore broken and likely to suffer collisions in browsers with bad `Math.random` implementations. Prefer [uuid](https://www.npmjs.com/package/uuid) since it uses the `crypto` API where available. – Mark Amery Sep 23 '19 at 23:06
4

what's like this

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())
perona chan
  • 101
  • 1
  • 8
3

Here you can find a very small function that generates UUIDs.

One of the final versions is:

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
      )
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Pablo Pazos
  • 3,080
  • 29
  • 42
3

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

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

The UUID currently has a proposal for addition to the standard library and can be supported here ECMAScript proposal: JavaScript standard library 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 implementation 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.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
li x
  • 3,953
  • 2
  • 31
  • 51
  • The proposal currently is [proposing](https://github.com/WICG/uuid/blob/gh-pages/explainer.md#proposed-api-addition-to-crypto-interface) including it in the `crypto` interface: `const uuid = crypto.randomUUID(); // "52e6953d-edbe-4953-be2e-65ed3836b2f0"` – M. Justin Jul 15 '21 at 20:16
3

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.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 */
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Bennett Barouch
  • 125
  • 1
  • 3
  • 10
3

Here is a function that generates a static UUID from a string or a random UUID if no string supplied:

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

vanowm
  • 9,466
  • 2
  • 21
  • 37
3

Easy to do with a simple uuid package https://www.npmjs.com/package/uuid

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

Based on the highest rated answer by @broofa here is the simplest implementation of a guid in javascript with just 3 lines of code.

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

and when executed in console gives the following output. enter image description here

Vinod Srivastav
  • 3,644
  • 1
  • 27
  • 40
2

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 in client-side JavaScript code, it works well.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Rishi
  • 268
  • 1
  • 6
  • 4
    This literally [calls AWS S3](https://github.com/mongoh/tuid/blob/master/tuid.js#L50) to get a random ID. If calling a server is okay, you can just have the server generate a UUID. – Kasey Speakman Nov 23 '18 at 08:50
2

Here is a working example. It generates a 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)
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
2

For those who are using JavaScript on Windows (e.g., Windows Script Host (WSH), CScript, and HTA). 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 in any browser, not even Microsoft Edge! So, your mileage will vary with this answer.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Stephen Quan
  • 21,481
  • 4
  • 88
  • 75
2

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:

function uuidv4() {
  let bytes = window.crypto.getRandomValues(new Uint8Array(32));
  const randomBytes = () => (bytes = bytes.slice(1)) && bytes[0];

  return ([1e7] + -1e3 + -4e3 + -8e3 + -1e11).replace(/[018]/g, c =>
      (c ^ randomBytes() & 15 >> c / 4).toString(16)
    );
}


for (var i = 0; i < 10; i++)
  console.log(uuidv4());

Collision:

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
user2226755
  • 12,494
  • 5
  • 50
  • 73
2

Don't use Math.random in any case since it generates a non-cryptographic source of random numbers.

The 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 you to understand the insecure randomness thrown by Fortify Scanner.

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Mohan Ram
  • 8,345
  • 25
  • 81
  • 130
2

UUID with timestamp built in (emitter/parser)

This is my simple approach to generating a valid UUID v4 with very strong uniqueness and fast runtime.

The basic idea is not new, but the approach is different. I use a timestamp in milliseconds from the date.now() (in the 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:

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

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:

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

Node.js

The NPM version of my code above available as a 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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
tarkh
  • 2,424
  • 1
  • 9
  • 12
  • This is *technically* not a compliant UUID4. It's neat that it has the timestamp, but you are better off using a UUID1 at that point. With this scheme, there's a 1 in 10,000 chance of a collision every time there is a millisecond collision, which if you emit events every second, that's 1/1000, or 1 in 10 million, every second. That's pretty much guaranteed to occur in any production bigger than basically hobby scale. Semantically, UUIDs shouldn't be timestamp fields. That's what timestamp fields are for. They are meant for "give me an ID which will NEVER collide". – DeusXMachina Sep 08 '20 at 19:30
  • 1
    @DeusXMachina thanks for commenting, I 100% agree. That's why in NodeJS library, which I've pointed at the end of my post, I use `process.hrtime.bigint()` for timestamps, which gives me nanosecond scale (1 million chance in a second) + random number from `10000` to `90000` at the end. So finally it goes to multi-billion chance in 1 sec, if my calculations is right. Anyway this is non-standard approach with specific use case, as I've mentioned above. – tarkh Sep 08 '20 at 23:04
  • 1
    Ah, I missed that. Perhaps edit your explanation so that it's a bit more obvious you are using ns resolution. "...produce a new UUID every millisecond + add a random 5-digit number". Still, why not use uuid1? That provides 0.1 µs resolution plus another 48 bits of entropy. https://en.wikipedia.org/wiki/Universally_unique_identifier#Version_1_(date-time_and_MAC_address) – DeusXMachina Sep 09 '20 at 14:12
  • Invalid should be `xxxxxxxx-xxxx-Mxxx-Nxxx-xxxxxxxxxxxx` – NVRM Nov 24 '20 at 06:13
  • @NVRM It IS valid, you can check result in any online UUID validators, i.e. here: https://www.freecodeformat.com/validate-uuid-guid.php – tarkh Nov 24 '20 at 09:51
  • @DeusXMachina , well because UUID1 is one way generator, which uses timestamp. Here you can extract timestamp back from your UUID) – tarkh Jun 26 '22 at 13:27
2

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 between 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 Explorer).

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Stefan Steiger
  • 78,642
  • 66
  • 377
  • 442
2

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

Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
smallscript
  • 643
  • 7
  • 13
2

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

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 a base for generating the UUID
let timePart = null; // Part of the UUID generated from Date.now()
let counter = 0; // Used for counting records created at certain millisecond
let lastTime = null; // Used for resetting the 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 the 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 the code only handles up to 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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
domaci_a_nas
  • 220
  • 2
  • 11
2

this offering returns 5 groups of 8 digits from a-z,0-9 most of it is random, however incorprates time of day, and has a randomly incrementing counter. you can specify any base you like (hex, decimal, 36), by default chooses a random base for each group of 8, in the range of base 16 to 36

function newId(base) {
return[
 Math.random,
 function (){ return (newId.last ? windowId.last + Math.random() : Math.random() ) },
 Math.random,
 Date.now,
 Math.random
].map(function(fn){
    return fn().toString(base||(16+(Math.random()*20))).substr(-8);
}).join('-');
}

var demo = function(base){
    document.getElementById('uuid').textContent = newId(base);
}
demo(16);
#uuid { font-family: monospace; font-size: 1.5em; }
<p id="uuid"></p>
<button onclick="demo(16);">Hex (base 16)</button>
<button onclick="demo(36);">Base 36</button>
<button onclick="demo(10);">Decimal (base 10)</button>
<button onclick="demo();">Random base</button>
unsynchronized
  • 4,828
  • 2
  • 31
  • 43
2

The coolest way:

function uuid(){
    var u = URL.createObjectURL(new Blob([""]))
    URL.revokeObjectURL(u);
    return u.split("/").slice(-1)[0]
}

It's probably not fast, efficient, or supported in IE2 but it sure is cool

Explosion
  • 328
  • 2
  • 10
2

I use this version. It is safe and simple. It is not to generate formatted uids, it is just to generate random strings of chars you need.

export function makeId(length) {
  let result = '';
  const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
  const charactersLength = characters.length;

  for (let i = 0; i < length; i++) {
    let letterPos = parseInt(crypto.getRandomValues(new Uint8Array(1))[0] / 255 * charactersLength - 1, 10)
    result += characters[letterPos]
  }
  return result;
}
Slava
  • 1,559
  • 1
  • 12
  • 17
1

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;
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Matthew Riches
  • 2,298
  • 18
  • 26
1

In the case of IDs generated more than one millisecond apart, they are guaranteed to be unique.

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

Based on the same method, if two IDs are generated at less frequent intervals, then they would be 99.99% likely to be globally unique (collision in 1 out of 10^15).

Adding more digits will increase this number, but a global counter will generate 100% unique IDs.

The following format will pass as a valid GUID for version 4 if you need RFC compatibility:

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

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/

lugreen
  • 102
  • 1
  • 8
0
function randomHex(length) {
    var random_string = '';
    if(!length){
        length = 1;
    }
    for(var i=0; i<length; i+=1){
        random_string += Math.floor(Math.random() * 15).toString(16);
    }
    return random_string;
}

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

The following is not v4 compliant, but it could easily be altered to be. It's 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
    }
}
Peter Mortensen
  • 30,738
  • 21
  • 105
  • 131
Jacob Ochoa
  • 81
  • 1
  • 3
0
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);  
   });  
}
Yudner
  • 533
  • 4
  • 9
0

For situations where you already have created a URL for some resource through utilizing the URL.createObjectURL method, you probably won't do faster or shorter than the following:

const uuid = url => url.substr(-36);

The above will work with any compliant implementation of createObjectURL, since the specification explicitly mandates a UUID be added to the end of the URL returned by the former. So you are guaranteed the last 36 characters are the UUID part of the generated URL.

To be clear, sometimes -- heck, perhaps most of the time, everything considered -- you want to generate a UUID for something else than resources you create URLs for with createObjectURL. In those cases, calling the latter method on some new Blob() is going to absolutely tank the performance (and leak memory unless you clean up after yourself using the corresponding revokeObjectURL). It is still quite a "one-liner" though.

I do not recommend you use the above method just for generating UUIDs unless you already have URLs obtained through createObjectURL or something that has a UUID at the end.

I just wanted to mention the above variant for completeness.

Armen Michaeli
  • 8,625
  • 8
  • 58
  • 95
  • Do you have a working example that can run on the browser? – vsync Jan 12 '22 at 16:15
  • The answer is certainly valid for Web browsers and so the example above will work. – Armen Michaeli Jan 28 '22 at 12:33
  • I don't see any code example here which can be copy-pasted and tried in the console – vsync Jan 28 '22 at 12:56
  • I am not much in favour of writing answers where code must necessarily be copied for pasting in the console, among other places. The *usage context* seldom matches, so assume it would stand to reason those who need to make use of the answer are able to read it and understand and put it into use (adapting what code is presented among the prose that is there to explain it). It's all in the answer, really, is it not? Save for a literal body of code that can be copied and pasted in the console, I mean? – Armen Michaeli Jan 31 '22 at 12:43
  • I wanted to test this in the console to see what is the output. The Answer has a lot of text but I haven't read it because I don't have time to read long tests in answer, I want code which I can copy-paste. If I don't see such, I scroll to another answer – vsync Jan 31 '22 at 12:48
0

I Used this function and this is working correctly

function generateUUID(): string {
  let d = new Date().getTime();
  if (typeof performance !== 'undefined' && typeof performance.now === 'function'){
    d += performance.now(); //use high-precision timer if available
  }
  return 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function (c) {
    let r = (d + Math.random() * 16) % 16 | 0;
    d = Math.floor(d / 16);
    return (c === 'x' ? r : (r & 0x3 | 0x8)).toString(16);
  });
}

console.log(generateUUID())
-1

Here's a method that generates RFC4122 using true random via random.org. If the fetch fails it falls back to the browser's inbuilt crypto library which should almost be just as good. And finally, if the user's browser in question doesn't support that, it uses Math.random().

async function UUID() {
    //get 31 random hex characters
    return (await (async () => {
        let output;
        try {
            //try from random.org
            output = (await (
                await fetch('https://www.random.org/integers/?num=31&min=0&max=15&col=31&base=16&format=plain&rnd=new')
            ).text())
                //get rid of whitespace
                .replace(/[^0-9a-fA-F]+/g, '')
            ;
            if (output.length != 31)
                throw '';
        }
        catch {
            output = '';
            try {
                //failing that, try getting 16 8-bit digits from crypto
                for (let num of crypto.getRandomValues(new Uint8Array(16)))
                    //interpret as 32 4-bit hex numbers
                    output += (num >> 4).toString(16) + (num & 15).toString(16);
                //we only want 31
                output = output.substr(1);
            }
            catch {
                //failing THAT, use Math.random
                while (output.length < 31)
                    output += (0 | Math.random() * 16).toString(16);
            }
        }
        return output;
    })())
        //split into appropriate sections, and set the 15th character to 4
        .replace(/^(.{8})(.{4})(.{3})(.{4})/, '$1-$2-4$3-$4-')
        //force character 20 to the correct range
        .replace(/(?<=-)[^89abAB](?=[^-]+-[^-]+$)/, (num) => (
            (parseInt(num, 16) % 4 + 8).toString(16)
        ))
    ;
}

enter image description here

Hashbrown
  • 12,091
  • 8
  • 72
  • 95
  • 3
    One should never rely on external sources to generate one's randomness, especially when it comes to generating wallet addresses for instance. – Charaf Mar 13 '22 at 00:43
  • 2
    Then disable that part or point it at your own server farm? Not hard. But if you're supporting something that doesnt support `crypto` you *do not* want to be relying on `Math`. Who the hell is using client side random for wallet addresses anyway? If using node you'd call out to the OS for uuid generation. I actually don't get your point @Charaf – Hashbrown Mar 13 '22 at 02:40