co is a library that can wrap a generator function to a promise object, e.g.
function* add (x, y) {
var m = yield Promise.resolve(x);
var n = yield Promise.resolve(y);
return m + n;
}
co(add, 1, 2).then(sum => {
console.log(sum); // 3
});
But how does it work? What's the magic? Actually, it is internally walking the generator.
Let's define a simple co function takes a generator function as an argument, a promise returned:
function co (gfn) {
return new Promise((resolve, reject) => {
});
}
Create a generator object:
var g = gfn();
And next:
var ret = g.next();
if (ret.done) {
resolve(ret.value);
}
As you can see above, fulfill the promise if done. Or the value of ret should also be a promise object behind the yield expression. If this promise is fulfilled, we should call next() again. So, we create a function:
function done(m) {
var ret = g.next(m);
if (ret.done) {
resolve(ret.value);
} else {
ret.value.then(done, reject);
}
}
Finally we call done(). All codes:
function co () {
var gfn = arguments[0];
var args = Array.prototype.slice.call(arguments, 1);
return new Promise((resolve, reject) => {
var g = gfn.apply(null, args);
function done(m) {
var ret = g.next(m);
if (ret.done) {
resolve(ret.value);
} else {
ret.value.then(done, reject);
}
}
done();
});
}
Here we did not consider exceptions.
Now we use our co function:
co(all, 1, 2).then(sum => {
console.log(sum);// 3
})
This is core of co. It's not that complicated, just understand how to use ES2015's generator.