有点困惑q和nodejs承诺

我目前在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() 。 然而,我不确定我是如何将应用程序传递给它的,如果我需要返回它的callback以作为承诺来处理。

理想情况下,我不想通过我的代码开始重新启动Q我只希望它在我想删除金字塔用例的地方,所以在上面的例子中,我如何使用Q来承诺将应用程序传递到每个需要的模块然后在最后启动应用程序?

假设你的模块没有使用promise,你可以这样做:

 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.PromisePromise.allQ.all

或者,您可以将每个require(x)更改为Q.fcall(require,x)并直接使用Q.all ,但是这两者都很慢(尽pipeQ仍然很慢),并且比直接promisifying模块更容易出错。 最好提供可能的最低级别的API。

诺言不是厄运的callback金字塔的银弹。 我曾经看过代码,即使承诺它看起来像厄运的金字塔。

你可以通过做这样的事情来摆脱金字塔,并保持callback风格:

  // 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() {}