JavaScript 非同期処理 Promiseをループする

JavaScriptで複数のリソースの読み込みやWebスクレイピング等によるリソース取得時に「XMLHttpRequest」を使い非同期で読み込みたい時があります。

最近ではPromiseで非同期処理をするのが一般的ですがforの中にPromiseを入れても意味がありません。

  for(i=0; i < 10; i++){
    let a = new Promise((resolve, reject)=>{
      setTimeout(()=>{
        console.log("foo");
        return resolve();
      })
    })
  }

  console.log("bar");

Output

bar
foo(10)

この様にPromise自体は実行されますが、forの中身が実行されている間に次のconsole.log("bar");が実行されてしまいます。

解決方法

条件が合うまで同じ関数を呼び出す方式でループを実現します。

  function PromiseLoop(a, c, b = 0){
    if(b >= a){
      return Promise.resolve();
    }else{
      return c(b).then(()=>{
        return PromiseLoop(a, c, b + 1);
      });
    }
  }
  • a : 繰り返し回数
  • c : 関数 (戻り値はPromise.resolve()である必要がある)
  • b : 条件初期化

引数cにはreturnにPromise.resolve()を返す必要があります。 Promiseを返さないとthen()で次の処理が動きません。

      return c(b).then(()=>{
        return PromiseLoop(a, c, b + 1);
      });

引数bは特に指定が無い限り初期値を0に初期化します。 これは省略可能な引数です。

使用例

これは関数を10回繰り返すサンプルです。

  PromiseLoop(10, (index)=>{
    console.log(`foo${index}`);
    return Promise.resolve();
  }).then(()=>{
    console.log("END");
  });

Output

foo0
foo1
foo2
・・・
foo9
END

第三引数bを変えて繰り返す範囲を絞る事も可能です。 これは配列の特定の要素範囲をロードする際に活用出来ます。

  PromiseLoop(10, (index)=>{  // 5 >= 10
    console.log(`foo${index}`);
    return Promise.resolve();
  }, 5).then(()=>{
    console.log("END");
  });

コメント

このブログの人気の投稿

Qt ウィンドウのあれこれ

Qt setWindowFlagsについて

Qt レイアウト 余白の処理