We learned JavaScript knowing that functions execute from top-to-bottom, just like we read English from right-to-left. That all changed when ES6 was released in June of 2016, bringing with it the ability to pause functions in the middle of execution.
How does this work? Generators! Also known as Generator Functions.
A generator function can be paused at any given point and continue where it left off when told to do so. Pretty crazy, right?
Let's take a look at a basic example.
Creating a JavaScript Generator Function
Generator functions in JavaScript are created much like any other function, except for one difference in syntax. Can you spot it?
function* tacoIngredients() {
yield 'Shell';
yield 'Meat';
yield 'Lettuce';
yield 'Cheese';
}
The difference is in the function definition itself - generator functions are written using the function*
syntax.
The JavaScript Generator Yield Keyword
You probably noticed the yield
keyword in the example above. When a generator function is called, it executes until it encounters a yield
expression. At this point, the generator function pauses, returns the value defined after the yield
keyword, and waits to continue execution until the function is called again.
Returning Values from JavaScript Generator Functions
Here's another difference between Generators and regular functions in JavaScript: generator functions return its value in a wrapped object. Why? Because technically, Generators conform to the Iterator protocol (think Maps and Observables), which means the wrapped object looks like this:
{
value, // the next value you want to get from the generator function
done; // a flag informing you if this is the last value in the sequence
}
If we wanted to get the data in the tacoIngredients
function defined in the example above, it would look something like this:
function* tacoIngredients() {
yield 'Shell';
yield 'Meat';
yield 'Lettuce';
yield 'Cheese';
}
const taco = tacoIngredients();
console.log(taco.next()); // { value: 'Shell', done: false }
Each time we call the next()
method, an object is returned in the shape mentioned prior. To get the data, simply access the value
property. Because the done
property has a value of false, we know there is more data to be retrieved and we can call the generator again.
function* tacoIngredients() {
yield 'Shell';
yield 'Meat';
yield 'Lettuce';
yield 'Cheese';
}
const taco = tacoIngredients();
console.log(taco.next()); // { value: 'Shell', done: false }
console.log(taco.next()); // { value: 'Meat', done: false }
console.log(taco.next()); // { value: 'Lettuce', done: false }
console.log(taco.next()); // { value: 'Cheese', done: false }
console.log(taco.next()); // { done: true }
If we call next()
after the generator has encountered its last yield
keyword, it returns an object with a single property - and it's probably what you're expecting - done
is set to true!
Wrapping Up
JavaScript Generator Functions are really cool - and I hope this article helped you understand how to use them in your own projects!
Want a real-world example? Here's a CodePen demo I made that calculates the Fibonacci sequence using JavaScript Generator Functions!
Resources
- Understanding Generators in ES6 JavaScript with Examples
- A Simple Guide to Understanding Javascript (ES6) Generators
- JavaScript Generators
Thanks for reading! If you enjoyed this article, consider sharing it on Twitter and signing up for my developer newsletter below so you don't miss out on my future content!
Cover photo by Chris Dickens / Unsplash