Thunk以及CO模块
co4.0之前都是返回的thunk函数
以后的都是返回promise
thunk
thunk:在 JavaScript 语言中,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);
};
};
临盆环境中,能够运用thunkify将函数转换为thunk 函数
题目:
为何node 内里大部分的callback都是第一个参数是err呢?
为何要做thunk 转换呢?
在redux内里也有thunk middleware,这个thunk是什么意义呢?
CO 模块
co的道理很简单,就是将传入的generator function 转换为一个thunk,而且转换后thunk 的generator的每一个value值作为下一个状况的输入
function co(fn) {
var isGenFun = isGeneratorFunction(fn); return function (done) {//返回的thunk函数,done 作为回调函数 var ctx = this; // in toThunk() below we invoke co() // with a generator, so optimize for // this case var gen = fn; //gen function 转换为generator if (isGenFun) { var args = slice.call(arguments), len = args.length; var hasCallback = len && 'function' == typeof args[len - 1]; done = hasCallback ? args.pop() : error; gen = fn.apply(this, args); } else { done = done || error; } //函数实行的时刻就会实行next函数,进入函数体内里 next(); // #92 // wrap the callback in a setImmediate // so that any of its errors aren't caught by `co` function exit(err, res) { setImmediate(done.bind(ctx, err, res)); } function next(err, res) { var ret; // multiple args if (arguments.length > 2) res = slice.call(arguments, 1); // error if (err) { try { ret = gen.throw(err); } catch (e) { return exit(e); } } // ok if (!err) { try { ret = gen.next(res); } catch (e) { return exit(e); } } // done if (ret.done) return exit(null, ret.value); // normalize ret.value = toThunk(ret.value, ctx); // run if ('function' == typeof ret.value) { var called = false; try { //比方实行yield readFile('test.json'), ret.value就是readFile函数,函数接收一个callback,callback挪用next要领,讲readFile的效果传入了next函数 ret.value.call(ctx, function(){ //这里能够防备next函数被屡次实行 if (called) return; called = true; next.apply(ctx, arguments); }); } catch (e) { setImmediate(function(){ if (called) return; called = true; next(e); }); } return; } // invalid next(new Error('yield a function, promise, generator, array, or object')); } } }
经由过程上面的co源码剖析,能够看下面的例子
co(function *() { var file = yield readFile('test.json'); //这里的file是经由过程gen.next() 赋值的 console.log(file); var ret = yield writeFile(file, 'dest.json'); console.log(ret); })
了解了这些基本概念后就能够进入koa的源码阅读了,详细的能够参考下一篇。