1. ホーム
  2. ジャバスクリプト

[解決済み】非同期のforEachコールバックがすべて完了した後にコールバックする。

2022-04-18 08:32:42

質問

タイトルの通りです。どうすればいいのでしょうか?

を呼び出したい。 whenAllDone() forEachループが各要素を通過し、非同期処理を行った後。

[1, 2, 3].forEach(
  function(item, index, array, done) {
     asyncFunction(item, function itemDone() {
       console.log(item + " done");
       done();
     });
  }, function allDone() {
     console.log("All done");
     whenAllDone();
  }
);

このように動作させることは可能でしょうか?forEachの第2引数がコールバック関数で、それがすべての反復を通過した後に実行される場合?

期待される出力

3 done
1 done
2 done
All done!

解決方法は?

Array.forEach はこのような機能を提供しませんが、あなたが望むことを実現するための方法がいくつかあります。

単純なカウンターを使用する

function callback () { console.log('all done'); }

var itemsProcessed = 0;

[1, 2, 3].forEach((item, index, array) => {
  asyncFunction(item, () => {
    itemsProcessed++;
    if(itemsProcessed === array.length) {
      callback();
    }
  });
});

(@vanuan と他の人に感謝) このアプローチは、"done" コールバックを呼び出す前にすべてのアイテムが処理されることを保証します。コールバックで更新されるカウンターを使用する必要があります。index パラメータの値に依存すると、非同期処理の戻り順が保証されないため、同じ保証は得られません。

ES6プロミスの使用

(古いブラウザではプロミス・ライブラリが使用できます)。

  1. 同期実行を保証する全リクエストの処理(例:1→2→3)

    function asyncFunction (item, cb) {
      setTimeout(() => {
        console.log('done with', item);
        cb();
      }, 100);
    }
    
    let requests = [1, 2, 3].reduce((promiseChain, item) => {
        return promiseChain.then(() => new Promise((resolve) => {
          asyncFunction(item, resolve);
        }));
    }, Promise.resolve());
    
    requests.then(() => console.log('done'))
    
    
  2. 非同期リクエストをすべて同期実行せずに処理する(2が1より早く終了する可能性あり)

    let requests = [1,2,3].map((item) => {
        return new Promise((resolve) => {
          asyncFunction(item, resolve);
        });
    })
    
    Promise.all(requests).then(() => console.log('done'));
    
    

非同期ライブラリの使用

他にも非同期ライブラリがあります。 非同期 は、あなたが望むものを表現するためのメカニズムを提供する最も一般的なものです。

編集

質問本文が編集され、以前の同期のサンプルコードが削除されたので、明確にするために私の答えを更新しました。 元の例では、非同期の動作をモデル化するために同期のようなコードを使用していたので、次のように適用しました。

array.forEach シンクロナス であり、同様に res.write そのため、コールバックをforeachの呼び出しの後に置くだけでよいのです。

  posts.foreach(function(v, i) {
    res.write(v + ". index " + i);
  });

  res.end();