【问题标题】:Node.js, async module, concurrencyNode.js,异步模块,并发
【发布时间】:2015-11-20 22:49:50
【问题描述】:

我是否最好避免一次使用多个异步模块功能实例?

我的代码分三部分依次执行。我正在使用类似的代码

var async = require('async');
async.waterfall(
  [ function(cb) { part1(); },
    function(cb) { part2(); },
    function(cb) { part3(); }
  ],
  function(err, res) { console.log('Done'); }
);

part1() 也包含三个部分。其中第三个在前两个之后运行。我的想法是使用

function part1(err, res) {
  async.waterfall(
    [ function(cb) {
        async.parallel(
          [ function(cb) { part1a(); },
            function(cb) { part1b(); }
          ]
        );
      },
      function(cb) { part1c(); },
      function(cb) {
        if (err) return err('part 1 error')
        return res()
      }
    ]
  );
}

在 part1a 和 part1b 运行的地方,我使用了异步的三个特性:外部瀑布,以及 part1 中的瀑布和并行。我对 part1 进行了重组,只使用了一个功能:瀑布,part1a 然后 part1b 然后 part1c 只是为了让它工作。

我没有取得成功。例如,我没有看到“完成”消息。当我重组 part1 时,我接到了 part1a 的电话,但没有接到 part1b 或其他任何电话。

也许我并不孤单。在Optional callback not being called in the node.js async module's forEachOf method 中,@LuisDelgado 指出,“作为个人说明,到目前为止,我还没有成功地使异步与本身具有内部回调异步函数的函数很好地工作。”

在 Complicated use case for Node.js Async Module 中,@Robbie 和 @dark_shadow 发现 async.auto 取得了一些成功。我想这将涉及通过将我的三个外层函数分解为它们的组件并从外层调用每个组件来扁平化我的代码。也许这就是“JavaScript 方式”!

什么是对的?

提前致谢...

编辑:干得好,亚当萨克斯。非常感谢!后续...

编辑:亚当和其他人提出了承诺。 Adam 喜欢 bluebird,并展示了一些有用的语法。我遇到了蓝鸟问题,尽管它很吸引人。我在这里发布了一个后续的蓝鸟问题。通过此编辑,我将删除该后续问题,将此问题(如标题所示)保留为异步问题。

感谢那些鼓励我使用承诺的人,谢谢!请参阅node.js, bluebird, poor control of execution path。

仍然存在异步问题:我是否最好避免一次使用多个异步模块功能实例?

【问题讨论】:

  • 您需要在瀑布/并行函数各自的操作完成后调用回调cb 传递给它们
  • 使用 Promise 可以说更容易(也更易读)。 @ExplosionPills 如果您的句柄是对 Star Ocean 2 的引用,那么您刚刚成为我最喜欢的 SO 用户。
  • @ExplosionPills:谢谢。每个“我的”函数(“part1()”和 part1x())都有一个被调用的回调。如果你告诉我我应该调用我为异步(“cb”)添加的回调,那里有对我来说很有价值的信息。我在哪里称呼它们?
  • @BaldEagle,只要函数的异步部分完成,您就会调用它们,就像您在不使用 async 时调用回调一样。

标签: javascript node.js asynchronous async.js


【解决方案1】:

您可能想尝试使用Promises 进行这种异步操作的编排。 Promise 现在是 nodejs 和更新浏览器的原生 JS 功能。还有大量的 Promises 库。我用得最多的一个是bluebird,它有一些很棒的实用功能和额外的 Promise 糖。

对于你的例子,你会有类似的东西:

part1()
    .then(part2)
    .then(part3)
    .then(part4)
    .then(function() {
         console.log("Done!");
    });

function part1a() {
   return new Promise(function(resolve, reject){
     setTimeout(resolve, 1000);
   })
}

function part1() {
     return Promise.all([
         part1a(),
         part2b();
     ]);
}

【讨论】:

    【解决方案2】:

    我还建议在这种情况下使用 Promise,因为它们更好——更少的代码和单一的执行链和错误处理。如果要坚持使用异步,则需要在异步操作完成时调用传递给异步方法的回调。

    var async = require('async');
    async.waterfall(
      [ function(cb) { part1(cb); },
        function(cb) { part2(cb); },
        function(cb) { part3(cb); }
      ],
      function(err, res) { console.log('Done'); }
    );
    
    function part1(callbackFromAsync) {
      async.waterfall(
        [ function(waterfallCallback) {
            async.parallel(
              [ function(cb) { part1a(cb); },
                function(cb) { part1b(cb); }
              ], waterfallCallback // <- this needs to be called
            );
          },
          function(cb) { part1c(cb); },
          function(cb) {
              callbackFromAsync(); // <- this needs to be called!
          }
        ]
      );
    }
    

    实际上,每次异步操作完成时,都需要调用cb 函数来表示其完成。想象一下,part2、part3、part1a 等是更简单的函数,如下所示:

    function part(callback) {
      someAsyncOperation(function (err, result) {
        callback(err, result);
      });
    }
    

    您必须调用传递给该函数的回调来表示异步操作已完成。您使用回调传递错误(如果有)和结果(如果需要)备份函数堆栈。 callback 的调用是 async 知道你的异步函数完成的方式。

    【讨论】:

    • Explosion Pills 和 Adam Sax:谢谢你的时间。您分享了有关使用 async.js 的宝贵资料,还建议您使用 Promise。我已经想通了;更好。
    猜你喜欢
    • 2013-11-09
    • 2012-12-04
    • 2018-12-01
    • 1970-01-01
    • 2016-12-23
    • 2017-10-24
    • 2018-04-24
    • 2012-08-03
    • 2019-10-28
    相关资源
    最近更新 更多