generators
Generators are simply subtypes of Iterators which I wrote about previously. They are a special kind of function that can be suspended and resumed, which is making a difference to iterators. Generators use function* and yield operators to work their magic.
The yield operator returns a value from the function and when the generator is resumed, execution continues after the yield.
We also have to use function* (with star character) instead of a function to return a generator instance.
!!! Generators have been borrowed from Python language.
The most magical feature in ES6!
Why? Take a look:
1 function* generator () {
2 yield 1;
3 // pause
4 yield 2;
5 // pause
6 yield 3;
7 // pause
8 yield 'done?';
9 // done
10 }
11 let gen = generator(); // [object Generator]
12
13 console.log(gen.next()); // Object {value: 1, done: false}
14 console.log(gen.next()); // Object {value: 2, done: false}
15 console.log(gen.next()); // Object {value: 3, done: false}
16 console.log(gen.next()); // Object {value: 'done?', done: false}
17 console.log(gen.next()); // Object {value: undefined, done: true}
18 console.log(gen.next()); // Object {value: undefined, done: true}
19
20 for (let val of generator()) {
21 console.log(val); // 1
22 // 2
23 // 3
24 // 'done?'
25 }
As you can see, the generator has four yield statements. Each returns a value, pauses execution and moves to the next yield when next() method is called. Calling a function produces an object for controlling generator execution, a so-called generator object.
Use is similar to iterators. We have next() method as I mentioned above and we can even use it with for-of loop.
Below is an example of a generator called random1_10, which returns random numbers from 1 to 10.
1 function* random1_10 () {
2 while (true) {
3 yield Math.floor(Math.random() * 10) + 1;
4 }
5 }
6
7 let rand = random1_10();
8 console.log(rand.next());
9 console.log(rand.next());
10 // …
Generator has never ending while loop. It produces random numbers every time when you call next() method.
ES5 implementation:
1 function random1_10 () {
2 return {
3 next: function() {
4 return {
5 value: Math.floor(Math.random() * 10) + 1,
6 done: false
7 };
8 }
9 };
10 }
11
12 let rand = random1_10();
13 console.log(rand.next());
14 console.log(rand.next());
15 // …
We can also mix generators together:
1 function* random (max) {
2 yield Math.floor(Math.random() * max) + 1;
3 }
4
5 function* random1_20 () {
6 while (true) {
7 yield* random(20);
8 }
9 }
10
11 let rand = random1_20();
12 console.log(rand.next());
13 console.log(rand.next());
14 // …
random1_20 generator returns random values from 1 to 20. It uses random generator inside to create random number each time when yield statement is reached.