[UPDATE – 9/1/2011: ‘Seeing reports of UUID collisions in the wild. Johannes Baagoe has a write up on why Math.random() can’t be trusted. I’m not entirely sure I buy this, but I’m certainly less confident than before about the uniqueness of UUIDs generated using only Math.random().]
… as well as non-standard random IDs of arbitrary length and radix. For examples of the types of IDs it can generate, or to see performance data, check out the Math.uuid.js Test page.
Update 1/22/10: Math.uuid.js includes an Math.uuid2 Math.uuidCompact – an alternate implementation for RFC4122v4 UUIDs designed to be as compact as possible, and Math.uuidFast() – an implementation designed for performance.
Update 06/03/10: Several people have expressed concern over how random the Math.random() method is. (E.g. “If two clients load the random() lib at the same time, will they start with the same seed?”) After doing a bit of research into how various OSes handle random # generation , I’m pretty satisfied that this unlikely to be an issue. Seeding is done from a variety of sources of almost pure random numbers – mouse movement, built-in hardware support (e.g. by measuring noise in electrical circuits), various unique device IDs, BIOS checksums, memory usage statistics… and so on.
This is very interesting. Can I ask what you use it for? 🙂
@kris: Can you be more specific about the license incompatabilities? Any suggestions as to which license would be most appropriate for something like this?
@stephen: Sure. If you have a web app with a data model on the client, this allows the client to assign permanent IDs to objects when they are created, rather than having to issue a server request to get an ID (like you would normally have to do in a more traditional architecture.)
I think this has a bug that causes it to fail in IE7. IE7 does not allow you to extract characters from a string using square brackets, you have to use the .charAt() function.
Alternatively, you could change this line:
var c = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz’;
var c = ‘0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz’.split(”);
then c is an array and should work in all browsers.
Good Catch, Brian. I’ve updated the script to use the split() fix as you suggested. (If the code looks a little odd to anyone, it’s because I cache the split() version of the string on the function object. But in order to do that without requiring a cumbersome declaration outside of the function, I use arguments.callee to get the function object from within itself. It’s a little kludgy, but it keeps the method nice and self-contained.)
save to my Bookmarks 😉
What’s the license of this script? GPL, MIT?
BSD – It’s in the script source.
Update: Now dual MIT/GPL licensed.
var args = ARGS.shift(), length = args || 0, radix = args || 62;
Here is the specifi error:
A Runtime Error has occurred.
Do you wish to Debug?
Error: ‘0’ is null or not an object
This page is an awsome reference. I’d add this to the Wikkipedia UUID page if I know that this problem with IE is an isolated problem.
@Troy – Good catch. The problem was in the test page code, not the Math.uuid() function. ‘Just a trailing comma error, *dooh*. I’ve fixed it and it should be working now. Thanks for the report!
Wow! that was fast. Thanks for fixing this so quickly.
There is one typo that I found. The linked text for RFC4122 above is RFC4142
@Troy: Fixed. Thanks.
Is there a shorter version of the license text I could use along with a URL to the full license? I’d like to include a modified version of this script in some work and the license text is pretty bulky.
Sorry, leaving another comment so I get email updates.
Great, just what I was looking for for use in an Adobe AIR app that has client/server sync. Thanks much!
Licensing: I’m not sure what Kris means about the ‘viral clause’, but I also cannot include code in my open source releases unless it uses MPL or the MIT License. The MIT License is particularly simple and easy to use: http://www.opensource.org/licenses/mit-license.php
It would be great if you switched to the MIT License!
The revised BSD license is fully GPL compatible and OSI approved. It is essentially equivalent to the MIT License, and doesn’t have a viral clause. Hope that clears things up for anybody stumbling across this!
This code is now dual licensed under MIT and GPL. I’ve also shortened the verbiage to this effect in the source so it’s not so unwieldy.
Thanks! A real little gem 🙂
In regards to compliance with RFC 4122, 122 bits need to be independently randomly generated. Although I have not confirmed this, I think the reason is to (partly) deal with the issue of uniqueness in pseudo-random number generators. The Math.uuid.js code generates 31 random hex values. By generating random hex values instead of random bit values, are we not increasing the odds of generating duplicate UUIDs?
That’s a really good question. The only verbiage I see in rfc4122 about this is in section 4.4, where it says, “Set all the other bits to randomly (or pseudo-randomly) chosen values.” But I don’t read this as saying each bit must be generated by a unique call to a random number function. Random # generators are “in the business” of creating numbers where each bit is randomly set. So the hex values I’m using are simply clusters of 4 random bits produced by the Math.random() function.
In fact, there’s a good argument that *fewer* calls to Math.random() is better. Pseudo-random # generators are typically evaluated based on how many #’s they can produce before repeating. So by minimizing the # of calls, we’re maximizing the number of UUIDs we create before the generator begins repeating itself.
Math.uuidFast must set uuid to ‘4’ to be v4-compliant.
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
@George: Good catch, thanks! I’ve fixed uuidFast.
BTW, it seems like Math.random() is the biggest performance bottleneck. Do you have any feel for how David Bau’s implementation compares to the native one?
Also, is there really a need for a better RNG? I would expect the native implementations to be pretty good already. But I don’t have any concrete data for that assumption.
I didn’t benchmark Bau’s implementation of Math.random(), but it seems reasonable. I would expect it to be slower than most browser’s native implementation of Math.random(), but that the results are higher quality. He clearly knows quite a bit of math.
His Math.seedrandom() is very slow, however, if you let it gather entropy by walking the window object: about 700ms on Firefox, 100ms on other browsers that I tried. Much better to call his seedrandom with some server-generated random string like, perhaps, a real UUID or two 🙂
Thank you for that.
This really help to solve a task of tracking what a user does quick and dirty 🙂
Regarding your update on 6/3/2010 (I think this may have been in response to an e-mail I had written you around that time) – I don’t actually think most JS implementations actually use entropy sources in the OS. At least, I checked V8 specifically, and they seed their random number generator using the system time. Is it even possible to get to the OS entropy sources from the browser?