TL;DR: the essence of generator is controlling the suspension of code execution.
For generator itself, you can refer to this.
To sum up, there is three components you should distinguish: 1. generator function 2. generator 3. generated result
Generator function is simply the function
with star in its head and (optional) yield
in its body.
function *generator() {
console.log('Start!');
var i = 0;
while (true) {
if (i < 3)
yield i++;
}
}
var gen = generator();
// nothing happens here!!
Generator function itself does not do anything but return a generator, in the case above, gen
.
No console output here because only after the returned generator's next
method is called the body of generator function will run.
Generator has several methods, of which the most important one is next
. next
runs the code and returns the generator result.
var ret = gen.next();
// Start!
console.log(ret);
// {value: 0, done: false}
ret
above is generator result. It has two property: value
, the value you yield in generator function, and done
, a flag indicating whether the generator function return.
console.log(gen.next());
// {value: 1, done: false}
console.log(gen.next());
// {value: 2, done: false}
console.log(gen.next());
// {value: undefined, done: true}
At this point, no one will expect you to understand generator, at least not the async power of generator.
To put it simple, generator has two features:
- one can choose to jump out of a function and let outer code to determine when to jump back into the function.
- the control of asynchronous call can be done outside of your code
In code, yield
jumps outside of function, and next(val)
jumps back to the function and pass value back into the function.
Outside code can handle asynchronous call and decide proper time to switch to your own code.
Look the sample again:
var gen = generator();
console.log('generated generator');
console.log(gen.next().value);
// mock long long processing
setTimeout(function() {
console.log(gen.next().value);
console.log('Execute after timer fire');
}, 1000);
console.log('Execute after timer set');
/* result:
generated generator
start
0
Execute after timer set
1
Execute after timer fire
*/
See? The generator function itself does not handle callback. The outside code does.
The base is here. You can elaborate this code to support full asynchronousity while keeping generator function like sync one.
For example, suppose geturl
is an asynchronous call that returns a promise
object. you can write var html = yield getUrl('www.stackoverflow.com');
This jumps outside your code. And outside code will do stuff like:
var ret = gen.next();
ret.then(function (fetchedHTML) {
// jumps back to your generator function
// and assign fetchHTML to html in your code
gen.next(fetchedHTML);
});
For more complete guide, refer to this. And repository like co, galaxy, suspend and etc.