node的 thunkify模块说明
thunkify这种函数其实就是python的decorator方式,对目标方法进行一步步的wrap,但是这种方式和generator结合起来就会威力无穷了,实现自动异步功能。
thunkify使用一般分为三步,这里以fs.readFile这个非阻塞函数为例.
1.用thunkify wrap要调用的目标函数,这里是fs.readFile。
2.wrap目标函数 的普通参数,这里就是fs.readFile的文件名称
3.wrap目标函数 操作结束时的毁掉函数,这里是fs.readFile的 callback参数
node.js中的非阻塞api调用都是这个路子,如fs.readFile(fileName,callback);
thunkify注解
第一步:fn为fs.readFile
function thunkify(fn){ assert('function' == typeof fn, 'function required');
第二部:arguments为fs.readFile(filename,callback)的文件名称:filename return function(){ var args = new Array(arguments.length); var ctx = this; for(var i = 0; i < args.length; ++i) { args[i] = arguments[i]; }
第三步:done为fs.readLine(filename,callback)中的callback return function(done){ var called; args.push(function(){ if (called) return; called = true; done.apply(null, arguments); }); try { fn.apply(ctx, args); } catch (err) { done(err); } } } };
fs.readFile借用thunkify:
1.var readFile=thunkify(fs.readFile)
2.var fn=readFile('filename') 到此结束,还没真正开始调用系统api,一切都只是处于闭包缓存状态
3.fn(function callback(err,data){}) 到这里才开始真正的开始调用os api 读取文件数据了。
下面是从es 6 标准入门的一个例子改过来的:thunkif和generator 配合,自动完成非阻塞的读取文件。
var thunkify=require('thunkify'); var fs=require('fs'); var readFile=thunkify(fs.readFile); var generator=function* (){ for(var i=0;i<arguments.length;i++){ console.log('file: %s',arguments[i]); var r1=yield readFile(arguments[i]); //yield thunkify 最内部的 function (done){} 函数 console.log('r1: %s',r1); } } function rungenerator(generator){ //文件名称 var args=[]; for(var i=1;i<arguments.length;i++){ args.push(arguments[i]); } //生成generator实例 var gen= generator.apply(null,args); function next(err,data){ if(data){ console.log('data:',data.toString()); } //执行跳到 generator中去 var result=gen.next('abc'); if(result.done) {return;} //console.log('result: %s',result.value); result.value(next);//真正的调用,next作为回调 } next(); } rungenerator(generator,'1.js','2.js','3,js')
另外:python和javascript中的generator的差别还是很大的,python中的generator是个跛脚的东西,generator不能嵌套调用,没有实现彻底的实现,导致它的执行路线只能被封闭在同一个generator中。js中没有这个问题。