我目前在nodejs中有一些js文件,它们作为模块加载并扩充app对象(使用express)。
所以他们的签名看起来像:
module.exports = function(app, callback) {
// ...
callback();
}
所以目前我有大约5个我的代码看起来像:
require("./setup/a")(app, function() {
require("./setup/b")(app, function(){
require("./setup/c")(app, function(){
require("./setup/d")(app, function(){
require("./setup/e")(app, function(){
startApp();
})
})
})
})
});
现在看起来不像是它的厄运金字塔"但是我不完全确定我需要如何更改此模式以使用Q,因为我假设我会使用Q.fcall(...a).then(...b).etc.done()
。但是我不确定我是如何将应用程序传递给它的,如果我需要返回回调函数来处理它作为一个承诺。
理想情况下,我不想在我的代码中开始打击Q我只想在我想删除金字塔用例的地方使用它,所以在上面的示例中我如何使用Q与promises将应用程序传递到每个必需的模块,然后在最后启动应用程序?
答案 0 :(得分:2)
假设您的模块尚未使用承诺,您可以执行以下操作:
module.exports = function(app) {
// do some stuff with app
return new Promise(function(resolve,reject){
// when ready to resolve after some actions on app
resolve(); // you can also return a value here as a cb param
});
};
Promise.all(["./setup/a","./setup/b","./setup/c"].map(require.bind(null,app)))
.then(startApp);
然而,您应该尽可能使用最低级别的承诺,这意味着您只需返回您在此过程中使用的承诺:
module.exports = function(app){
return something(app).then(function(){
return somethingElseAsyncWithApp(app);
});
};
因此不需要promise构造函数。请注意,此答案使用本机承诺,但也适用于使用Bluebird等语法的库。对于Q,请将new Promise
更改为new Q.Promise
,将Promise.all
更改为Q.all
。
或者,您可以将每个require(x)
更改为Q.fcall(require,x)
并直接使用Q.all
,但这两者都很慢(尽管Q无论如何都很慢)并且比宣传更容易出错模块直接。最好是尽可能宣传最低级别的API。
答案 1 :(得分:0)
承诺不是回归厄运金字塔的银弹。我看过代码,即使有了承诺,它看起来像是一个厄运的金字塔。
您可以通过执行以下操作来摆脱金字塔并保持回调风格:
// var app;
// ...etc
var paths = ['a','b','c','d'];
setupNext();
function setupNext() {
var p = paths.pop(); // or shift
var next = paths.length > 0 ? setupNext : startApp
require(p)(app, next);
}
function startApp() {}