再说co之前要先搞清楚 Thunk函数和 Generator函数
Generator函数:
function* gen(x){
var y = yield x + 2;
return y;
}
var g = gen(1);
g.next() // { value: 3, done: false }
g.next() // { value: undefined, done: true }
简单来说Generator 可以让你拥有函数的控制权。上面代码中gen函数返回一个对象,这个对象中有value 和dong 两个值, value就是 函数中 yield 后面语句的值,而done 则用来判断函数时候执行完。你可以通过next()函数来执行代码,每次调用next 函数都会执行到 yield 并且返回后面语句的值。
Thunk函数:
// 正常版本的readFile(多参数版本)
fs.readFile(fileName, callback);
// Thunk版本的readFile(单参数版本)
var readFileThunk = Thunk(fileName);
readFileThunk(callback);
var Thunk = function (fileName){
return function (callback){
return fs.readFile(fileName, callback);
};
};
Thunk 可以让你把一个接受多参数的函数(至少要用一个回调函数作为参数)变成 接受单参数的函数。 上面代码中先用 Thunk函数 固定来一个参数 然后返回一个函数。这样,这个函数就只要接受一个回调作为参数。
Generator 跟 Thunk 配合使用 可以实现 Generator 函数自动执行
co是干啥用的
co 可以帮你自动执行Generator
直接看源码:
function co(gen) {
var ctx = this;
return new Promise(function(resolve, reject) {
if (typeof gen === 'function') gen = gen.call(ctx);
if (!gen || typeof gen.next !== 'function') return resolve(gen);
onFulfilled();
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
}
});
}
function next(ret) {
if (ret.done) return resolve(ret.value);
var value = toPromise.call(ctx, ret.value);
if (value && isPromise(value)) return value.then(onFulfilled, onRejected);
return onRejected(new TypeError('You may only yield a function, promise, generator, array, or object, '
+ 'but the following object was passed: "' + String(ret.value) + '"'));
}
});
co 函数接受 Generator 函数作为参数,返回一个 Promise 对象。
然后 在Promise中 需要判断一下 参数是不是Generator 函数,如果是就执行这个函数。这样就会得到一个新的对象,你可以通过这个对象的next 控制Generator 函数的执行,如果不是就返回,并将 Promise 对象的状态改为 resolved 。
onFulfilled 函数会调用上面返回的对象的next函数让Generator 函数进行下一步, onFulfilled 函数中用来try...catch 来捕获错误。
最后会执行next(ret) 这里的ret 是把上一阶段处理完毕的异步结果传入next函数。
next函数先通过参数中的done 来判断是否是Generator 函数的最后一步,如果是就返回。
然后给了确保 参数是Promise对象 把参数转换为Promise对象
使用then 传入两个回调 如果成功 就调用onFulfilled (调用自身)
如果失败 抛出一个错误,并且终止执行。