一个接一个地解决承诺(即按顺序)?

新手上路,请多包涵

考虑以下以串行/顺序方式读取文件数组的代码。 readFiles 返回一个承诺,只有在所有文件都按顺序读取后才会解决。

var readFile = function(file) {
  ... // Returns a promise.
};

var readFiles = function(files) {
  return new Promise((resolve, reject) => {
    var readSequential = function(index) {
      if (index >= files.length) {
        resolve();
      } else {
        readFile(files[index]).then(function() {
          readSequential(index + 1);
        }).catch(reject);
      }
    };

    readSequential(0); // Start with the first file!
  });
};

上面的代码有效,但我不喜欢为了顺序发生的事情而进行递归。有没有更简单的方法可以重写这段代码,这样我就不必使用我奇怪 readSequential 函数了?

最初我尝试使用 Promise.all ,但这导致所有 readFile 调用同时发生,这 不是 我想要的:

var readFiles = function(files) {
  return Promise.all(files.map(function(file) {
    return readFile(file);
  }));
};

原文由 XåpplI‘-I0llwlg’I - 发布,翻译遵循 CC BY-SA 4.0 许可协议

阅读 346
2 个回答

2017 年更新:如果环境支持,我会使用异步函数:

 async function readFiles(files) {
 for(const file of files) {
 await readFile(file);
 }
 };

如果您愿意,您可以推迟读取文件,直到您需要使用异步生成器(如果您的环境支持):

 async function* readFiles(files) {
 for(const file of files) {
 yield await readFile(file);
 }
 };


更新:再想一想 - 我可能会使用 for 循环:

 var readFiles = function(files) {
 var p = Promise.resolve(); // Q() in q

 files.forEach(file =>
 p = p.then(() => readFile(file));
 );
 return p;
 };

或者更紧凑,使用 reduce:

 var readFiles = function(files) {
 return files.reduce((p, file) => {
 return p.then(() => readFile(file));
 }, Promise.resolve()); // initial
 };

在其他 Promise 库(如 when 和 Bluebird)中,您有用于此目的的实用方法。

例如,蓝鸟将是:

 var Promise = require("bluebird");
 var fs = Promise.promisifyAll(require("fs"));

 var readAll = Promise.resolve(files).map(fs.readFileAsync,{concurrency: 1 });
 // if the order matters, you can use Promise.each instead and omit concurrency param

 readAll.then(function(allFileContents){
 // do stuff to read files.
 });

尽管今天确实没有理由 使用 async await。

原文由 Benjamin Gruenbaum 发布,翻译遵循 CC BY-SA 4.0 许可协议

以下是我更喜欢按顺序运行任务的方式。

 function runSerial() {
    var that = this;
    // task1 is a function that returns a promise (and immediately starts executing)
    // task2 is a function that returns a promise (and immediately starts executing)
    return Promise.resolve()
        .then(function() {
            return that.task1();
        })
        .then(function() {
            return that.task2();
        })
        .then(function() {
            console.log(" ---- done ----");
        });
}


有更多任务的案例呢?比如,10?

 function runSerial(tasks) {
  var result = Promise.resolve();
  tasks.forEach(task => {
    result = result.then(() => task());
  });
  return result;
}

原文由 Andreas Åkre Solberg 发布,翻译遵循 CC BY-SA 3.0 许可协议

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题