与nodejs中的q和promises有点混淆

时间:2014-07-27 15:00:04

标签: javascript node.js promise q

我目前在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将应用程序传递到每个必需的模块,然后在最后启动应用程序?

2 个答案:

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