在JavaScript中我想覆盖对象上的函数,但仍然调用原始函数并返回它的值。所以我通常会这样做:
var render = res.render;
res.render = function() {
doSomethingNew();
return render.apply(this, arguments);
};
但是,如果该覆盖包含需要在调用原始函数之前首先触发的异步回调,例如:
var render = res.render;
res.render = function() {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
return callNextMiddleware(middlewares, function() {
return render.apply(self, args);
});
};
function callNextMiddleware(middlewares, callback) {
var middlewareFunc = middlewares.shift();
if (middlewareFunc) {
return middlewareFunc.call(function() {
return callNextMiddleware(middlewares, callback);
});
}
else {
return callback();
}
}
请注意,我在需要时使用'return'语句。我有一个问题,'middlewares'变量是一个函数数组,每个中间件函数看起来像这样:
function myMiddleware(next) {
performLongRunningAsyncDataAccess(function() {
next();
});
}
因为它不使用'return next()',所以原始res.render方法的返回值永远不会被传回。如果我让所有中间件函数都使用'return next()',我可以让它工作,但它们来自外部源,所以我无法控制它们,我只能保证它们会调用'next()'
有点背景,这是一个Node.js应用程序。中间件基本上是连接中间件,我试图覆盖Express.js res.render方法。
答案 0 :(得分:2)
通常,将异步函数与return
语句混合是一个坏主意。您要返回的所有内容,都可以作为参数传递给回调函数。所以我仍然希望我能正确理解你的代码但是我会假设你调用render
函数,然后它会抓取一组middleware
函数。然后你想要执行该数组中的所有函数,使用next作为前一个回调。执行完所有函数后,应再次调用render
函数,从而创建一种无限循环。假设所有这些,让我们看看你的一些return
语句:
return middlewareFunc.call(function() {
return callNextMiddleware(middlewares, callback);
});
此块中的第一个return
无用,因为middlewareFunc
是异步的,因此最有可能返回undefined
。第二个return
语句也没用,因为它从函数返回,用作回调。但由于您的回调仅使用next();
调用,因此永远不会使用返回值。
else {
return callback();
}
在此块callback
中是render
功能。让我们来看看这个函数:
res.render = function() {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
return callNextMiddleware(middlewares, function() {
return render.apply(self, args);
});
};
因此,所有最后三个return
语句基本上都存在,因为您希望从render
函数返回一些内容。但为了保持一致,你应该考虑使用该函数的回调:
res.render = function(callback) {
var self = this;
var args = arguments;
var middlewares = getSomeMiddleware();
callNextMiddleware(middlewares, function() {
//this will be called after all the middleware function have been executed
callback();
render.apply(self, args);
});
};
所以基本上你摆脱了所有return
语句并使用纯异步设计模式。
答案 1 :(得分:1)
callNextMiddleware
应返回其递归调用的返回值,而不是middlewareFunc
的。
if (middlewareFunc) {
var result;
middlewareFunc.call(this, function() {
result = callNextMiddleware(middlewares, callback);
});
return result;
}