[javascript] How to create a GUID / UUID

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

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

The function is as simple as:

/**
 * Generates a GUID string.
 * @returns {string} The generated GUID.
 * @example af8a8416-6e18-a307-bd9c-f2c947bbb3aa
 * @author Slavik Meltser.
 * @link http://slavik.meltser.info/?p=142
 */
function guid() {
    function _p8(s) {
        var p = (Math.random().toString(16)+"000000000").substr(2,8);
        return s ? "-" + p.substr(0,4) + "-" + p.substr(4,4) : p ;
    }
    return _p8() + _p8(true) + _p8(true) + _p8();
}

To test the performance, you can run this code:

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

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

The algorithm:

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

The assembly:

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

Link to this post on my blog

Enjoy! :-)