考虑下面以串行/顺序方式读取文件数组的代码。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。但是这会导致所有的readFile调用并发发生,这不是我想要的:

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

当前回答

我能想到的最好的解决办法就是蓝鸟承诺。你可以执行Promise.resolve(files).each(fs.readFileAsync);这保证了承诺是按顺序被解决的。

其他回答

这是对如何以更通用的方式处理承诺序列的扩展,支持基于spex的动态/无限序列。序列实现:

var $q = require("q");
var spex = require('spex')($q);

var files = []; // any dynamic source of files;

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

function source(index) {
    if (index < files.length) {
        return readFile(files[index]);
    }
}

function dest(index, data) {
    // data = resolved data from readFile;
}

spex.sequence(source, dest)
    .then(function (data) {
        // finished the sequence;
    })
    .catch(function (error) {
        // error;
    });

这种解决方案不仅适用于任何大小的序列,而且还可以轻松地向其添加数据节流和负载平衡。

只需使用.then(resPrevTask => nextTask())

(顺便说一下,下一个代码需要4秒。)

函数task1() { return new Promise((resolve) => { setTimeout(() => { 解决(console.log(任务1)) }, 3000) }) } 函数task2() { return new Promise((resolve) => { setTimeout(() => { 解决(console.log(任务2)) }, 1000) }) } 函数seqTasks () { task1 () .then(() => task2()) } seqTasks ();

您的方法还不错,但它确实有两个问题:它会吞下错误,并且使用显式承诺构造反模式。

你可以解决这两个问题,并使代码更干净,同时仍然采用相同的一般策略:

var Q = require("q");

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

var readFiles = function(files) {
  var readSequential = function(index) {
    if (index < files.length) {
      return readFile(files[index]).then(function() {
        return readSequential(index + 1);
      });
    }
  };

  // using Promise.resolve() here in case files.length is 0
  return Promise.resolve(readSequential(0)); // Start!
};

你可以使用这个函数来获取promiseFactories List:

function executeSequentially(promiseFactories) {
    var result = Promise.resolve();
    promiseFactories.forEach(function (promiseFactory) {
        result = result.then(promiseFactory);
    });
    return result;
}

Promise Factory是一个简单的函数,返回一个Promise:

function myPromiseFactory() {
    return somethingThatCreatesAPromise();
}

它之所以有效,是因为承诺工厂直到被要求才创建承诺。它的工作方式与then函数相同——事实上,它是一样的!

你根本不想在一组承诺上操作。根据Promise规范,一旦创建了Promise,它就开始执行。所以你真正想要的是一系列的承诺工厂…

如果你想了解更多的承诺,你应该检查这个链接: https://pouchdb.com/2015/05/18/we-have-a-problem-with-promises.html

数组push和pop方法可用于承诺序列。当你需要额外的数据时,你也可以推出新的承诺。这是代码,我将使用在React无限加载器加载页面序列。

var promises = [Promise.resolve()]; 函数methodThatReturnsAPromise(page) { 返回新的承诺((resolve, reject) => { setTimeout(() => { console.log(“解决- ${页面}!${new Date()} '); 解决(); }, 1000); }); } 函数pushPromise(page) { promises.push (promises.pop()。然后(function () { 返回methodThatReturnsAPromise(页面) })); } pushPromise (1); pushPromise (2); pushPromise (3);