Generators in JavaScript

In this article, we will understand what Generators are and how we can make use of them in our code.

What are Generators?

It's like a regular javascript function but can return a value more than once and at a defined period of time. Ok, what do you mean?

This comes with a concept called yielding. Just like on the road how cars yield to the other vehicles passing by from time and time again, we can make our functions yield (return) a value as and when required.

Let's understand with a simple snippet:

function* sayHelloManyTimes() {
    yield "Hello";
    yield "hello";
    yield "HELLO";
}

.next()

In order for that to be called, we need to use .next() what works like the iterators to return the next yield value.

// Let's assign this to a variable `func` so we can easily
// call multiple times.
const func = sayHelloManyTimes();

If you're curious like me, this is what would get printed to the console when we log func.

So, we can see that it has a prototype of GeneratorFunctionPrototype.

console.log(func.next());

If you do a .next(), you will get the first yield value printed with additional details.

{
    value: "Hello"
    done: false
}

As you can see only one of the yield values is returned and also notice done: false that indicates there are some more yields still present. Just like Iterators.

In fact, Generators are used in the background in implementing Iterables. Async/await depends on Generators and Promises in the background.

We can keep doing .next() until we get done: true which happens in this case after 4 times.

console.log(func.next());
console.log(func.next());
console.log(func.next());

Just like .next(), the are other methods like .return() and .throw()

.return()

.return() just like a normal function terminates the function at that given state of the yield and returns a value if an argument is provided in the .return(arg) or simply returns undefined.

function* sayHelloManyTimes() {
  yield "Hello";
  yield "hello";
  yield "HELLO";
}

const func = sayHelloManyTimes();
console.log(func.next());
console.log(func.return("finish"));

// Prints
// {value: "Hello", done: false}
// {value: "finish", done: true}

// even though there are other yields still pending.

.throw()

.throw() lets you throw an error from the generator which can be caught using try/catch.

function* sayHelloManyTimes() {
  try {
    yield "Hello";
    yield "hello";
    yield "HELLO";
  } catch (err) {
    console.log("Error: ", err);
  }
}

const func = sayHelloManyTimes();
console.log(func.next());
console.log(func.throw("error"));

// Prints

// {value: "Hello", done: false}
// Error:  error 
// {value: undefined, done: true}

If you have come down all this far, I hope you liked this article. If yes, please read my other articles on promises, javascript, interview-questions, ...

You can even subscribe to the newsletter to receive the article directly in your inbox.

#2Articles1Week

Cheers

Arunkumar Sri Sailapathi.