Node.js 如何等待所有异步调用完成

Node.js 如何等待所有异步调用完成,node.js,mongoose,Node.js,Mongoose,我将Mongoose与Node.js一起使用,下面的代码将在所有save()调用完成后调用回调。然而,我觉得这是一种非常肮脏的方式,我希望看到正确的方式来完成这件事 function setup(callback) { // Clear the DB and load fixtures Account.remove({}, addFixtureData); function addFixtureData() { // Load the fixtures fs.re

我将Mongoose与Node.js一起使用,下面的代码将在所有save()调用完成后调用回调。然而,我觉得这是一种非常肮脏的方式,我希望看到正确的方式来完成这件事

function setup(callback) {

  // Clear the DB and load fixtures
  Account.remove({}, addFixtureData);

  function addFixtureData() {
    // Load the fixtures
    fs.readFile('./fixtures/account.json', 'utf8', function(err, data) {
      if (err) { throw err; }
      var jsonData = JSON.parse(data);
        var count = 0;
        jsonData.forEach(function(json) {
          count++;
          var account = new Account(json);
          account.save(function(err) {
            if (err) { throw err; }
            if (--count == 0 && callback) callback();
          });
        });
    });
  }
}

这实际上是正确的做法,或多或少。你在那里做的是一个平行循环。如果您愿意,您可以将其抽象为自己的“async parallel foreach”函数(许多人都这么做),但这实际上是执行并行循环的唯一方法

根据您的意图,有一件事情可以做得不同,那就是错误处理。因为您正在抛出,如果只有一个错误,那么该回调将永远不会执行(
count
不会递减)。因此,最好是:

account.save(function(err) {
  if (err) return callback(err);
  if (!--count) callback();
});
并处理回调中的错误。这是最好的节点约定明智

我还想改变另一件事,以避免在每次迭代中增加
count
的麻烦:

var jsonData = JSON.parse(data)
  , count = jsonData.length;

jsonData.forEach(function(json) {
  var account = new Account(json);
  account.save(function(err) {
    if (err) return callback(err);
    if (!--count) callback();
  });
});

您可以使用或之类的库稍微清理代码

此外,我还编写了一个小模块,用于为您处理装载夹具的问题,因此您只需执行以下操作:

var fixtures = require('./mongoose-fixtures');

fixtures.load('./fixtures/account.json', function(err) {
  //Fixtures loaded, you're ready to go
};
Github:


它还将加载夹具文件或对象的目录。

我讨论了常见的异步模式(串行和并行)及其解决方法:


我希望它有用。

如果您已经在项目中的任何地方使用过,您可以利用该方法。您需要提前知道将有多少异步调用,但除此之外,这是一个非常优雅的解决方案。

我最近创建了一个更简单的抽象,名为wait.for以同步模式调用异步函数(基于光纤)。这是在早期阶段,但工作。网址为:

使用wait.for,您可以调用任何标准的nodejs异步函数,就好像它是一个同步函数一样,而不会阻塞节点的事件循环。您可以在需要时按顺序编码

使用wait.for您的代码将是:

//in a fiber
function setup(callback) {

  // Clear the DB and load fixtures
  wait.for(Account.remove,{});

  // Load the fixtures
  var data = wait.for(fs.readFile,'./fixtures/account.json', 'utf8');

  var jsonData = JSON.parse(data);
  jsonData.forEach(function(json) {
    var account = new Account(json);
    wait.forMethod(account,'save');
  }
  callback();
}

如果使用fixtures库,我建议使用以下更新的项目,它更快、维护更积极:是。。pow mongodb夹具速度更快,但mongoose夹具将验证您的夹具是否符合mongoose模型(例如字段匹配等)。它还可以使用虚拟属性,这对于夹具数据来说非常方便。这就是开发人员有时所说的“”。解释如何防止这种情况。我喜欢使用有助于防止意大利面代码的库,例如来自Caolan McMahon的库。可以在中找到更多)。我使用一个函数来实现此功能。像这样简单的实用程序功能会有很大帮助。