一旦所有异步readFile()调用完成,如何确定

时间:2015-11-11 21:54:23

标签: javascript node.js

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

1 个答案:

答案 0 :(得分:0)

一般策略是通过从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);
      }
    }
  }
}

可以像:

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

如果您使用的是节点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']).then(function (results) {
  var oneTxtContents = results[0];
  var twoTxtContents = results[1];
});

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

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

async.map(['one.txt', 'two.txt'], fs.readFile, function (err, results) {
  var oneTxtContents = results[0];
  var twoTxtContents = results[1];
});

对于基于Promise的并行异步任务,您可以使用像Q这样的Promise库,其中包含用于fs.readFile等节点式函数“promisification”的实用程序:

// 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];
});