DEV Community

Cover image for Generating UUIDs with JavaScript Generators
Terfa Binda
Terfa Binda

Posted on

Generating UUIDs with JavaScript Generators

I first heard about the term UUID in 2010 while coding with Microsoft Visual Basic, but UUIDs have been around a lot longer than that. Some developers refer to it as GUIDs. They both represent the same concept.

Globally Unique Identifier
GUID stands for Globally Unique Identifier these days developers prefer to call it UUID which means Universally Unique Identifier. These abbreviations refer to the same thing, but UUID is the term we shall be using going forward.

A UUID is a 128-bit label that is used to identify any resource or entity with a very high probability of uniqueness. A UUID is generated by following a standard or complex algorithm that combines different sources of randomness such as timestamps, MAC addresses, namespaces, names, or random numbers.

There are different flavors and formats of UUIDs. Each one depends on a specific algorithm and the representation used. The most common format is a string of 32 hexadecimal digits, separated by hyphens into five groups, such as 550e8400-e20b-a796–446655440000. The first group indicates the version of the UUID, and the last group denotes the flavor of the UUID.

Currently, there are five known versions of UUIDs and four variants defined by the RFC 4122 standard.

You may need to create a UUID in JavaScript if you want to have a unique and consistent way of identifying resources, such as files, objects, or components, across different systems or platforms. For example, if you are developing a web application that needs to store or sync data with a server or a database, you can use UUIDs as keys or identifiers for your data. This way, you can avoid conflicts or collisions with other data that may have the same name or ID. UUIDs play an indispensable role when generating random passwords, secure tokens, or unique identifiers are required.

UUIDs may be generated using different methods and algorithms or a specific library such as uuid. You can also use a specialized command line tool to generate one. Or you can write a concise JavaScript Generator function that generates a random UUID following the xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx pattern. This is also the main objective of this writeup

What are JavaScript Generators?

Let’s now beam our searchlights on Generators. These are a special type of function object in JavaScript that are capable of returning multiple (and in some cases continuous) values on demand.

In contrast, normal functions return single values or nothing. When invoked a normal function predictably executes the same code from beginning to the point where it encounters a return statement, and either returns a specified value or nothing. For example:

function doSomething(a, b){

  let sum = a + b;
  return sum;

}
Enter fullscreen mode Exit fullscreen mode

Generator functions are a little different. They are declared with a different syntax as follows:

function* doSomething(a, b){
  return 'Hello Generator function!'
}
Enter fullscreen mode Exit fullscreen mode

or

function *doSomething(a, b){
  return 'Hello Generator function!'
}
Enter fullscreen mode Exit fullscreen mode

The distinguishing element is the asterisk * operator that is appended to the end of the function keyword or prepended to the name of the function. Generator functions return generator objects not primitive values as normal functions do. Let’s see this in the code example below:

function* generatorFunction() {
    return 'Hello Generator!'
}

const generatorFn = generatorFunction();
console.log(generatorFn)

//output:
generatorFunction {<suspended>}
  __proto__: Generator
  [[GeneratorLocation]]: VM272:1
  [[GeneratorStatus]]: "suspended"
  [[GeneratorFunction]]: ƒ* generatorFunction()
  [[GeneratorReceiver]]: Window
  [[Scopes]]: Scopes[3]
Enter fullscreen mode Exit fullscreen mode

The generator objects returned by Generator functions are sometimes called iterators. Iterator objects come with a next() method, a mechanism that moves the iterator cursor through a sequence of values. Therefore, the outputting code will be:

// Call the next method on the Generator object
console.log(generatorFn.next());
Enter fullscreen mode Exit fullscreen mode

This will render the following output:

//output:
{value: "Hello Generator!", done: true}
Enter fullscreen mode Exit fullscreen mode

What have we learned from the foregoing? We can see that the message returned by invoking next() is “Hello Generator!”, and the status of done is true. This indicates that the iterator has completed its run. From this moment the generator function’s status will change from suspended to closed. Invoking generatorFn again will give you an updated information about the current state of the generator which will be revealed as follows:

//output:
generatorFunction {<closed>}
Enter fullscreen mode Exit fullscreen mode

Generator functions work better when used in combination with the yield operator. The yield operator gives generator functions the ability to pause code execution and return the current value when the next() is invoked on it. Let’s assume we create a generator function as follows:

// Create a generator function with multiple yields
    function* generatorFunction() {
        yield 'California'
        yield 'Colorado'
        yield 'Georgia'
        return 'Indiana'
    }

    const generatorFn = generatorFunction()
Enter fullscreen mode Exit fullscreen mode

Therefore invoking the next() method on the generatorFn will cause the function to pause at each step while returning a value. The value of done will remain false until the final value is returned: For example:

console.log(generator.next());
console.log(generator.next());
console.log(generator.next());
console.log(generator.next());


//output:
{value: "Mercury", done: false}
{value: "Venus", done: false}
{value: "Mars", done: false}
{value: "Jupiter", done: true}
Enter fullscreen mode Exit fullscreen mode

In fact it is not even necessary to use a return statement in a generator. Generators are self-aware of the last iteration and will return {value:undefined, done:true}. Every subsequent call to next() will have the same effect after a generator’s iterations are completed.

The yield operator gives Generators its powers, especially in situations where working with infinite data streams and collections is desired. We can demonstrate this use case by creating an infinite loop within a generator function, that is made to keep incrementing a number as follows:

// Define a generator function that increments by one
function* increment() {
    let i = 0
    while (true) {
      yield i++
    }
  }

  // Initiate the generator
const counter = increment();

//print in console
console.log(counter.next());
console.log(counter.next());
console.log(counter.next());
console.log(counter.next());
console.log(counter.next());

//output
{ value: 0, done: false }
{ value: 1, done: false }
{ value: 2, done: false }
{ value: 3, done: false }
{ value: 4, done: false }
Enter fullscreen mode Exit fullscreen mode

The function returns a chain of values in an infinite loop while the done property remains false, thus ensuring that the increment function never halts. Even though the while(true) code block appears to be caught in an unending loop, execution is paused after each yield and resumed only when the iterator’s next method is invoked in the console.log code. The stateful value of the local i variable remains unchanged between each call and is maintained.

You are completely safe when an infinite loop with generators because it gives you the power to pause and resume execution at any time. This is the innovativeness that generators bring to JavaScript; the awesome ability to pause and resume code execution in between calls. However, you must exercise caution when using the generator in combination with the spread or for..of on an infinite data stream, which can create an uncontrollable infinite loop that could eventually cause the environment to crash.

Generating GUIDs With JavaScript Generators
We can now combine the innovative use of a generator function in JavaScript with a nifty function that can give us an endless front-end based UUID generator as follows:

function *guidGenerator() {
    while (true) {
        const uuidv4 = () => {
            // Generate a random number from 0 to 15
            function randomDigit () {
              return Math.floor (Math.random () * 16);
            }
            // Generate a random hex digit
            function randomHex () {
              return randomDigit ().toString (16);
            }
            // Generate a random segment of 4 hex digits
            function randomSegment () {
              return randomHex () + randomHex () + randomHex () + randomHex ();
            }
          // Generate a UUID following the 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx' pattern
            return randomSegment () + '-' + randomSegment () + '-4' 
+ randomSegment ().substring (1, 3) + '-' + randomHex () 
+ randomSegment ().substring (1, 3) + '-' + randomSegment () 
+ randomSegment ();
        }
        yield uuidv4();
    }
}

const getGuid = guidGenerator();

console.log(getGuid.next());
console.log(getGuid.next());
console.log(getGuid.next());
Enter fullscreen mode Exit fullscreen mode

This nifty generator function will yield the following output:

{ value: '4cec-6d60-490-c46-9d06f2c1', done: false }
{ value: '5c69-795f-421-a0e-82ef2cd0', done: false }
{ value: '497a-2065-4e3-bb4-d94f0dd0', done: false }
Enter fullscreen mode Exit fullscreen mode

To extract the string value out of the output object you should write the following lines:

const getGuid = guidGenerator();
console.log(getGuid.next().value);
console.log(getGuid.next().value);
console.log(getGuid.next().value);

//output
bac4-3650-4af-10a-5836de95
9f71-f4f2-489-11f-965f03ef
c18f-d3cd-4a0-2c4-1458bdf4
Enter fullscreen mode Exit fullscreen mode

Since UUIDs are meant to be unique, you should expect a different output on your machine.

In conclusion, generating UUIDs in JavaScript using generator functions is a straightforward process that can be accomplished by following the steps outlined in this article, you can easily create unique identifiers for your applications, ensuring data integrity and avoiding conflicts. Whether you're working on a small project or a large-scale system, UUIDs provide a reliable way to manage unique data entries.

If you found this guide on UUID generation helpful and want to explore more advanced JavaScript techniques, check out my book, Concise JavaScript: For Beginners and Advanced Learners, available on Amazon. It’s packed with practical insights to enhance your coding skills!

Thanks for reading and have happy coding session!

Top comments (0)