Generators are functions that can pause execution midway through and then continue from where they stopped.
A standard function in JavaScript runs until it returns or executes its last line of code. Invoking the function again causes it to begin execution from the start. In contrast, a Generator can stop midway and yield a return value. Invoking the Generator again resumes the execution from where it last left off.
The following illustration highlights this difference:
A generator can be declared either of the following two ways:
function * myGenerator () {}
// or
let myGenerator = function * () {}
Generators return an object that has two properties: value (the yielded value) and done (shows us whether or not the generator has finished its job). Consider the following code snippet where the done
property becomes true
once the generator has yielded all of its values:
function * generator() {yield 5;}const gen = generator();console.log(gen.next());console.log(gen.next());
Generators are useful because, instead of returning all the values, a value is only yielded when it is needed. The following example highlights this:
function * generator() {let a = 5;yield a + 1;a = 10;yield a + 5;}const gen = generator();console.log(gen.next().value);console.log("...Doing some other work after getting a yield...")console.log(gen.next().value);
Generators also take arguments and are reusable:
function * generator(arg = 'Empty') {yield arg;}const gen0 = generator();console.log(gen0.next().value);const gen1 = generator('Hi');console.log(gen1.next().value);
Generators are iterable themselves; hence, they can be used to implement iterables with very few lines of code:
function * generator() {yield 'This';yield 'is';yield 'iterable.'}for (const val of generator()) {console.log(val);}
Another very handy use case is that generators allow the creation of infinite data streams. In the example below, note how the generator is suspended after yielding a value from an infinite loop:
function * naturalNumbers() {let num = 1;while (true) {yield num;num = num + 1}}const numbers = naturalNumbers();console.log(numbers.next().value);console.log(numbers.next().value);console.log("...some other work...");// ... can get another value anytime from the paused generator.console.log(numbers.next().value);