co & thunkify

时间:2021-11-21 14:32:15

co

之前在generator中已经介绍过Co了

戳这里

http://www.cnblogs.com/cart55free99/p/4893498.html

co一般和thunkify一起使用 能够使得generator用起来更方便 所以co就是一个generator的流程控制模块

以fs.readFile作为例子

先把readFile thunkify一下

fs.readFile(filename, callback)

变成

readThunk(filename)(callback)

这样的调用形式

co的用法

co(function* (){
var fs1 = yield readThunk('a.txt', 'utf8');
var fs2 = yield readThunk('b.txt', 'utf8');
//...
})

你可以像Async那样用同步的方式书写异步代码

这里的fs1 fs2就是 a.txt b.txt文件中的内容

真奇怪 fs1 fs2 的值应该是由 gen.next() 传入啊,

难道说 gen.next() 传入了 readThunk得到的文件内容?

没错 就是这样

下面简单说说co的源码

function co(gen) {
var ctx = this;
var args = slice.call(arguments, 1)
return new Promise(function(resolve, reject) {
gen = gen.apply(ctx, args); //onFulfilled实际上调用第一个gen.next();
onFulfilled(); //为了能够这样调用 var a = yield asyncFuntion();
//那么就需要将前一个async的返回值通过 gen.next()传给 变量a
//也就是将res这个值给a
function onFulfilled(res) {
var ret;
try {
ret = gen.next(res);
} catch (e) {
return reject(e);
}
next(ret);
} function onRejected(err) { ... } function next(ret) {
if (ret.done) return resolve(ret.value);
//将异步函数转为一个Promise对象 value是一个Promise对象
var value = toPromise.call(ctx, ret.value);
//判断是否是一个Promise对象 就是看是否有then()
if (value && isPromise(value)) return value.then(onFulfilled, onRejected); }
});
}

可见用一个Promise 来处理异步函数 将异步函数readFile的结果通过Filfilled这个callback再次调用gen.next() 所以fs1 fs2 就是文件内容

不过即使thunkify之后 至始至终貌似都只向 readThunk传了一个参数 callback呢?

仔细研究就会发现一般的回调函数都是 function(err, data)的形式 所以co在

thunkToPromise 中用一个通用的回调函数 不用自己写回调函数了

这个回调函数就是将 data resolve 并返回一个Promise

fn就是异步函数

  return new Promise(function (resolve, reject) {
fn.call(ctx, function (err, res) {
if (err) return reject(err);
if (arguments.length > 2) res = slice.call(arguments, 1);
resolve(res);
});
});

Promise success的那部分调用 Fulfilled 也就是再次调用了gen.next

co基本的处理流程就是这样