【问题标题】:A bit confused with q and promises in nodejs与 nodejs 中的 q 和 promises 有点混淆
【发布时间】:2016-08-10 02:59:37
【问题描述】:

我目前在 nodejs 中有一些 js 文件,它们作为模块加载并扩充应用程序对象(使用 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 和 Promise 将应用程序传递到每个必需的模块,然后在最后启动应用程序?

【问题讨论】:

    标签: javascript node.js promise q


    【解决方案1】:

    假设您的模块尚未使用 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);
    

    但是,您应该尽可能使用最低级别的 Promise,这意味着您可以简单地返回您在流程中使用的 Promise:

    module.exports = function(app){
         return something(app).then(function(){
             return somethingElseAsyncWithApp(app);
         });
    };
    

    因此不需要 promise 构造函数。请注意,此答案使用本机承诺,但也适用于使用该语法的库,如 Bluebird。对于 Q 更改 new Promisenew Q.PromisePromise.allQ.all

    或者,您可以将每个 require(x) 更改为 Q.fcall(require,x) 并直接在其上使用 Q.all,但这既慢(尽管 Q 无论如何都很慢)而且比直接承诺模块更容易出错。最好承诺最低级别的 API。

    【讨论】:

    • 感谢您的示例,所以Promise 是 Node 中可用的默认类的一部分吗?我认为它特定于 Q 或其他 Promise 库。我在我的构建脚本中在其他地方使用异步进行并行和系列调用,但正如我所知,在代码中的一些地方我想避免金字塔,x.then(y).then(z) 看起来更有吸引力,因为它更具可读性。同样在您的第一个示例中,应用程序如何传递到 Promise.all 调用中?
    • async 也可以在这里工作,但 Promise 是一个更强大的抽象。 Promise.all 聚合承诺,应用程序被传递到每个 require 调用 - 我忘了它,我会修复它。
    • 至于Promise - 这取决于节点的版本。就我个人而言,我会使用 Bluebird,它的堆栈跟踪比 Q 好得多,而且速度快两个数量级。
    • 好建议,会检查一下。我以前从来不需要承诺,所以没有过多研究,但是当我遇到金字塔式的情况时,做一些挖掘是有意义的。
    【解决方案2】:

    承诺不是回调末日金字塔的灵丹妙药。我见过代码,即使有承诺,它看起来也像是一个末日金字塔。

    您可以通过执行以下操作摆脱金字塔并保持回调样式:

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

    【讨论】:

      猜你喜欢
      • 2016-02-22
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-12-04
      • 2019-01-06
      • 1970-01-01
      相关资源
      最近更新 更多