Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
472 views
in Technique[技术] by (71.8m points)

javascript - 解决承诺一个接一个(即按顺序)?(Resolve promises one after another (i.e. in sequence)?)

Consider the following code that reads an array of files in a serial/sequential manner.

(考虑以下以串行/顺序方式读取文件数组的代码。)

readFiles returns a promise, which is resolved only once all files have been read in sequence.

(readFiles返回一个promise,仅当依次读取所有文件后,promise才会解析。)

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!

  });
};

The above code works, but I don't like having to do recursion for things to occur sequentially.

(上面的代码可以工作,但是我不喜欢必须递归使事情顺序发生。)

Is there a simpler way that this code can be re-written so that I don't have to use my weird readSequential function?

(有没有更简单的方法可以重写此代码,这样我就不必使用怪异的readSequential函数了?)

Originally I tried to use Promise.all , but that caused all of the readFile calls to happen concurrently, which is not what I want:

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

var readFiles = function(files) {
  return Promise.all(files.map(function(file) {
    return readFile(file);
  }));
};
  ask by X?pplI'-I0llwlg'I - translate from so

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Update 2017 : I would use an async function if the environment supports it:

(2017年更新 :如果环境支持,我将使用异步功能:)

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

If you'd like, you can defer reading the files until you need them using an async generator (if your environment supports it):

(如果需要,可以使用异步生成器(如果您的环境支持)将读取文件的时间推迟到需要它们之前:)

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

Update: In second thought - I might use a for loop instead:

(更新:再次考虑-我可能会使用for循环:)

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

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

Or more compactly, with reduce:

(或更紧凑地使用减少:)

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

In other promise libraries (like when and Bluebird) you have utility methods for this.

(在其他Promise库(如when和Bluebird)中,您可以使用此方法。)

For example, Bluebird would be:

(例如,蓝鸟将是:)

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.
});

Although there is really no reason not to use async await today.

(尽管今天确实没有理由使用异步等待。)


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...