以前在generator中已经介绍过Co了javascript
co通常和thunkify一块儿使用 可以使得generator用起来更方便 因此co就是一个generator的流程控制模块
以fs.readFile做为例子java
先把readFile thunkify一下
从app
fs.readFile(filename, callback)
变成异步
readThunk(filename)(callback)
这样的调用形式async
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的源码this
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呢?code
仔细研究就会发现通常的回调函数都是 function(err, data)的形式 因此co在
thunkToPromise 中用一个通用的回调函数 不用本身写回调函数了
这个回调函数就是将 data resolve 并返回一个Promisehtm
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基本的处理流程就是这样