只接受回调函数作为参数的单参数函数叫做 Thunk 函数。
Thunk 函数可以用于 Generator 函数的自动流程管理。使Generator 函数可以自动执行
任何函数,只要参数有回调函数,就能写成 Thunk 函数的形式。
下面是一个将多参函数转换成thunk函数的转换器
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| var Thunk = function(fn){ return function (){ var args = Array.prototype.slice.call(arguments); return function (callback){ args.push(callback); return fn.apply(this, args); } }; }; var Thunk = function(fn) { return function (...args) { return function (callback) { return fn.call(this, ...args, callback); } }; };
|
生产环境的转换器,建议使用 Thunkify 模块。
npm install thunkify
thunk配合Generator进行异步操作
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| function run(fn) { var gen = fn(); function next(data) { var result = gen.next(data); if (result.done){ console.log("done"); return; }; result.value(next); } next(); } function request(data,cb) { setTimeout(function(){ cb(data+1); },1000); } function* g() { console.log("start"); var a = yield Thunk(request)(1); console.log(a); var b = yield Thunk(request)(2); console.log(b); var c = yield Thunk(request)(3); console.log(c); console.log("end"); } run(g);
|
最终的输出结果是
start
2
3
4
end
done
2、3、4间隔1s输出
首先通过Thunk方法将request方法转换成Thunk函数,上面代码的run函数,是一个 Generator 函数的自动执行器。内部的next函数就是 Thunk 的回调函数(最终就是request中的cb参数)。next函数先将指针移到 Generator 函数的下一步(gen.next方法),然后判断 Generator 函数是否结束(result.done属性),如果没结束,就将next函数再传入 Thunk 函数(result.value属性),否则就直接退出。
有了这个执行器,执行 Generator 函数方便多了。不管内部有多少个异步操作,直接把 Generator 函数传入run函数即可。当然,前提是每一个异步操作,都要是 Thunk 函数,也就是说,跟在yield命令后面的必须是 Thunk 函数。
所以上面的request可以改写
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17
| function request(data){ return function(cb){ setTimeout(function(){ cb(data+1); },1000); } } function* g() { console.log("start"); var a = yield request(1); console.log(a); var b = yield request(2); console.log(b); var c = yield request(3); console.log(c); console.log("end"); }
|
就不用Thunk进行转换了