1. ホーム
  2. javascript

[解決済み] 約束事を次々と解決していく(=順番に解決していく)?

2022-03-15 11:40:01

質問

ファイルの配列をシリアル/シーケンシャルに読み取る次のコードを考えてください。 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);
  }));
};

解決方法は?

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

他のプロミスライブラリ(whenやBluebirdなど)には、このためのユーティリティメソッドがあります。

例えば、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.
});

特に理由はないのですが ない は、今日、非同期awaitを使用します。