只接受回调函数作为参数的单参数函数叫做 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进行转换了