co
Generator functions can also be used to control code execution flow. By using yield
expressions, we can control when the execution of a generator object should be suspended. When the execution of a generator object is suspended, other code can have the chance to run and choose the best time to resume the execution. yield*
expressions allow the delegation to other generator objects or iterable objects, which can create complicated nested or recursive execution flows.
Generator functions are most useful when combining with Promise
s. As described in MDN,
The Promise object is used for asynchronous computations. A Promise represents a value which may be available now, or in the future, or never.
If the value of a yield
expression is a Promise
object, then we can suspend the execution of the generator object when waiting for the Promise
to be resolved. When the Promise
is fulfilled, we can resume the execution of the generator object with the fulfilled value as the value of the yield
expression. Otherwise, we can finish the generator with the rejected error.
To support this kind of scenarios, we need to use the library co. In the code below, timeoutToPromise
is a helper method that creates a Promise
object using setTimeout
. Generator function calculate
uses yield
expression and the Promise
object created by timeoutToPromise
. co(calculate, 1, 2)
turns the generator function calculate
into a Promise
object.
const co = require('co');
function timeoutToPromise(action, timeout) {
return new Promise(function(resolve, reject) {
setTimeout(function() {
resolve(action());
}, timeout);
});
}
function *calculate(v1, v2) {
return yield timeoutToPromise(function() {
return v1 + v2;
}, 1000);
}
co(calculate, 1, 2).then(function (value) {
console.log(value);
}, function (err) {
console.error(err);
});
// -> Output 3 after about 1s delay
Below is an example of using co
with generator functions which have yield
expressions with other generator objects. value
is a generator function which takes the argument v
as the seed of generating two random values v1
and v2
. yield value(1)
in calculate
uses a generator object value(1)
as the target of yield
expression.
const co = require('co');
function *value(v) {
return yield {
v1: v + Math.random() * 100,
v2: v + Math.random() * 500
};
}
function *calculate() {
const values = yield value(1);
return values.v1 + values.v2;
}
co(calculate).then(function (value) {
console.log(value);
}, function (err) {
console.error(err);
});
// -> Output random number