Javascript 如何确定所有异步readFile()调用完成后

Javascript 如何确定所有异步readFile()调用完成后,javascript,node.js,Javascript,Node.js,我在文件目录上循环,对于每个位置,我都使用异步fs.readFile()读取该目录中的文件。如何最好地确定所有异步readFile()调用是否已完成?一般策略是通过从fs.readFile回调中增加共享计数器来跟踪已读取的文件数。然后,当这个计数器等于文件总数时,您就知道完成了。例如: function readFiles(paths, callback) { var processed = 0, total = paths.length; // holds results

我在文件目录上循环,对于每个位置,我都使用异步
fs.readFile()
读取该目录中的文件。如何最好地确定所有异步
readFile()
调用是否已完成?

一般策略是通过从
fs.readFile
回调中增加共享计数器来跟踪已读取的文件数。然后,当这个计数器等于文件总数时,您就知道完成了。例如:

function readFiles(paths, callback) {
  var processed = 0,
      total = paths.length;

  // holds results (file contents) in the same order as paths
  var results = new Array(total);

  // asynchronously read all files
  for (var i = 0, len = files.length; i < len; ++i) {
    fs.readFile(paths[i], doneFactory(i));
  }

  // factory for generating callbacks to fs.readFile
  // and closing over the index i
  function doneFactory(i) {
    // this is a callback to fs.readFile
    return function done(err, result) {
      // save the result under the correct index
      results[i] = result;

      // if we are all done, callback with all results
      if (++processed === total) {
        callback(results);
      }
    }
  }
}

如果您在节点0.11.13或更高版本上,还可以使用本机承诺,特别是
Promise.all
,它接受一系列承诺并等待所有承诺得到解决:

function readFiles(paths) {
  // for each path, generate a promise which is resolved
  // with the contents of the file when the file is read
  var promises = paths.map(function (path) {
    return new Promise(function (resolve, reject) {
      fs.readFile(path, function (err, result) {
        if (err) {
          reject(err);
        } else {
          resolve(result);
        }
      });
    });
  });

  return Promise.all(promises);
}
可以像这样使用:

readFiles(['one.txt', 'two.txt'], function (results) {
  var oneTxtContents = results[0];
  var twoTxtContents = results[1];
});
readFiles(['one.txt', 'two.txt']).then(function (results) {
  var oneTxtContents = results[0];
  var twoTxtContents = results[1];
});

最后,有许多库使这项(相当常见的)任务变得更容易

对于基于回调的并行异步任务,可以使用库:

对于基于Promise的并行异步任务,您可以使用Promise库,如,它包含节点样式函数的“promisification”实用程序,如
fs.readFile

// this is not the only way to achieve this with Q!
Q.all(['one.txt', 'two.txt'].map(function (path) {
  // call "promisified" version of fs.readFile, return promise
  return Q.nfcall(fs.readFile, path);
})).then(function (results) {
  // all promises have been resolved
  var oneTxtContents = results[0];
  var twoTxtContents = results[1];
});

promise图书馆在这里会有所帮助-您是否签出了
bluebird
?在这种情况下,这有什么帮助?这还不只是处理单个异步调用吗?不,你可以使用Bluebird循环异步调用并映射结果-好的,谢谢-这很有意义。我最终使用了tymeJV对Bluebird的建议,并使用了它的
.map()
,它基本上就是你所描述的。
// this is not the only way to achieve this with Q!
Q.all(['one.txt', 'two.txt'].map(function (path) {
  // call "promisified" version of fs.readFile, return promise
  return Q.nfcall(fs.readFile, path);
})).then(function (results) {
  // all promises have been resolved
  var oneTxtContents = results[0];
  var twoTxtContents = results[1];
});