search
LoginSignup
8

More than 1 year has passed since last update.

posted at

配列に格納されている async 関数を順番に実行したい

前哨

for await なんて便利な物があるではないか

以下そのまま転載

const asyncIterable = {
  [Symbol.asyncIterator]() {
    return {
      i: 0,
      next() {
        if (this.i < 3) {
          return Promise.resolve({ value: this.i++, done: false });
        }

        return Promise.resolve({ done: true });
      }
    };
  }
};

(async function() {
   for await (let num of asyncIterable) {
     console.log(num);
   }
})();

// 0
// 1
// 2

つまり内部に Promiseawait があるイテレータを for ループで回せる訳ですね。
とすれば配列にたくさん Primise ぶちこんで、こんなかんじに回してあげれば逐次実行できる訳です。

// 関数を遅延実行できるようにする
lazyFunction = (f, ...args) => {
  return () => f(...args)
}

async executePromiseSerearize(ps) {
  const rs = []
  // ps を頭から実行するイテレータを作る
  const executer = async function*(ps){
    const _ps = [].concat(ps)
    while(_ps.length){
      const p = _ps.shift()
      yield await p()
    }
  }
  // イテレータを for of で実行
  for await(const r of executer(ps)){
    rs.push(r)
  }
  return rs
}

// 1秒後に n が出力されて n が帰ってくる
const hogehoge = (n) => new Promise((resolve, reject) => {
  setTimeout(() => {
    console.log(n)
    resolve(n)
  }, 1000)
})

const ps = [1,2,3,4,5].map(n => lazyFunction(hogehoge, n))

!(async () => {
  res = await executePromiseSerearize(ps)
  console.log(res)
})()
// 1 から 5 が1秒毎に出力されて最後に配列が出る

でも eslint では非推奨

書いてある事をざっくり言うと 「なんで async でプロセスが並列で処理できるのに逐次実行しようとするの??なんで時間の無駄遣いをしようとするの??バカなの??*ぬの???:angry::angry::angry::angry:

という事ですが……例えばさぁ……WEBスクレイピングするのに何万ページ一気に開いてアクセスするとか……もうDDoS攻撃レベルじゃないですか……

というわけで

非推奨の物でも、使わなきゃいけない事がある。おします。

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
What you can do with signing up
8