thunkify源码阅读困惑
/**
* Module dependencies.
*/
var assert = require('assert');
/**
* Expose `thunkify()`.
*/
module.exports = thunkify;
/**
* Wrap a regular callback `fn` as a thunk.
*
* @param {Function} fn
* @return {Function}
* @api public
*/
function thunkify(fn){
assert('function' == typeof fn, 'function required');
return function(){
var args = new Array(arguments.length);
var ctx = this;
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
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);
}
}
}
};
疑问:
return function(done) 这一行开始,返回一个thunk后的函数, 如果我写的话,就直接 done.apply(null, arguments); 了。。。。
不知道往args里push东西到底什么含义。。。求指点
try-catch这部分也看不明白。。。
10 回复
// fn 原来是这样调用的 fn ( [arg1,] [arg2,] [...] callback )
function thunkify(fn){
assert('function' == typeof fn, 'function required');
// 返回这个函数接收前面的参数 [arg1,] [arg2,] [...]
return function(){
var args = new Array(arguments.length);
var ctx = this;
// 先把 [arg1,] [arg2,][...] 部分保存起来, 放 args 里
for(var i = 0; i < args.length; ++i) {
args[i] = arguments[i];
}
// 这里返回的函数接收最后一参数 callback
return function(done){
// 把传进来的 callback部分 push 进 args里
// [arg1,] [arg2,] [...] callback
// 这样 args 就变成了 fn 期望接收的参数形式
// 这用一个called作为标识, 把 callback 包了一下, 保证这个包装过的callback只被执行一次
var called;
args.push(function(){
if (called) return;
called = true;
done.apply(null, arguments);
});
try {
// 最终执行的还是原来的函数, args 也包含了 callback
fn.apply(ctx, args);
} catch (err) {
done(err);
}
}
}
};
@reverland
args.push
是为了把callback放进args
, 把args
构造成原来fn
所预期的, 最后的参数是callback的形式, 然后下面才可以用args
作为参数调用原来的fn
, 本来可以写成这样
args.push(done);
而实际的代码把done包了一层, 应该是防止callback执行多次吧
@captainblue2013 我刚接触js不久,不是很清楚。然而记得ydkjs上讲过回调被多次调用是一个问题,把控制权给他的程序并不能知道回调执行了几次什么的。promise设计就只能resolve或者reject一次,保证回调只运行一次。 自豪地采用 CNodeJS ionic
@captainblue2013 具体怎么想的我也不太清楚, 应该是保证callback即使被不小心错误的调用多次, 结果也只是执行一次 , 例如下面
// 因为程序员的失误 ,next 被调用2次
var middleware=function(req,res,next){
if( req.auth ){
req.userInfo={name:"tom"};
next();
}
next();
}