286

タイトルが示すように。どうすればいいですか?

whenAllDone()forEach-loop が各要素を通過し、非同期処理を行った後に呼び出したいと思います。

[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!
4

14 に答える 14

18

非同期のケースにどれだけ多くの間違った回答が与えられたかは奇妙です! インデックスをチェックしても期待どおりの動作が得られないことを簡単に示すことができます。

// INCORRECT
var list = [4000, 2000];
list.forEach(function(l, index) {
    console.log(l + ' started ...');
    setTimeout(function() {
        console.log(index + ': ' + l);
    }, l);
});

出力:

4000 started
2000 started
1: 2000
0: 4000

をチェックするとindex === array.length - 1、最初の反復が完了するとコールバックが呼び出されますが、最初の要素はまだ保留中です!

非同期などの外部ライブラリを使用せずにこの問題を解決するには、リストの長さを節約し、反復ごとにデクリメントするのが最善の策だと思います。スレッドが 1 つしかないため、競合状態が発生する可能性はないと確信しています。

var list = [4000, 2000];
var counter = list.length;
list.forEach(function(l, index) {
    console.log(l + ' started ...');
    setTimeout(function() {
        console.log(index + ': ' + l);
        counter -= 1;
        if ( counter === 0)
            // call your callback here
    }, l);
});
于 2015-11-15T10:54:56.413 に答える
17

これで問題が解決することを願っています。内部で非同期タスクを使用して forEach を実行する必要がある場合は、通常これを使用します。

foo = [a,b,c,d];
waiting = foo.length;
foo.forEach(function(entry){
      doAsynchronousFunction(entry,finish) //call finish after each entry
}
function finish(){
      waiting--;
      if (waiting==0) {
          //do your Job intended to be done after forEach is completed
      } 
}

function doAsynchronousFunction(entry,callback){
       //asynchronousjob with entry
       callback();
}
于 2015-11-12T14:31:14.220 に答える
0

これは、非同期の Node.js のソリューションです。

async npm パッケージを使用します。

(JavaScript) forEach ループを内部のコールバックと同期する

于 2015-03-04T08:14:30.680 に答える
0
var i=0;
const waitFor = (ms) => 
{ 
  new Promise((r) => 
  {
   setTimeout(function () {
   console.log('timeout completed: ',ms,' : ',i); 
     i++;
     if(i==data.length){
      console.log('Done')  
    }
  }, ms); 
 })
}
var data=[1000, 200, 500];
data.forEach((num) => {
  waitFor(num)
})
于 2018-05-16T05:12:51.537 に答える
0

この質問でこれを達成するための多くの解決策と方法があります!.

ただし、マップasync/awaitを使用してこれを行う必要がある場合は、ここにあります

// Execution Starts
console.log("start")

// The Map will return promises
// the Execution will not go forward until all the promises are resolved.
await Promise.all(
    [1, 2, 3].map( async (item) => {
        await asyncFunction(item)
    })
)

// Will only run after all the items have resolved the asynchronous function. 
console.log("End")

出来上がりはこんな感じ!非同期関数によって異なる場合があります。

start
2
3
1
end

:マップでawaitを使用すると、常に promises 配列が返されます。

于 2021-12-13T20:02:29.930 に答える