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.
Cheers
Arunkumar Sri Sailapathi.