【TypeScript】Promise.allをmapで使う

  • TypeScript 3.5.1

Promise.all() の理解が曖昧だった。

const asyncFunc = async (prefix: string): Promise<void> => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`${prefix}_1秒待ちました`)
      return resolve()
    }, 1000)
  })
}

const main = async () => {
  const prefixes = ['A', 'B', 'C', 'D', 'E']
  const asyncFuncs: Promise<void>[] = []
  for (const prefix of prefixes) {
    asyncFuncs.push(asyncFunc(prefix)) // 実行開始
  }
  console.log('Promise.all前')
  await Promise.all(asyncFuncs).then(() => console.log('完了')) // すべてPromiseを返すまで待つ
  console.log('Promise.all後')
}

main()

こんなサンプルを書いてみた。

勘違いしていたのが、実は asyncFuncs.push(asyncFunc(prefix)) の段階ですでに実行は始まっているという点。 await Promise.all の箇所で実行開始するのかと思っていたが、あくまでこいつは引数配列に含むすべてのPromiseが返ってくるのを待つという動作をする。 その証拠にこの行をコメントアウトしても console.log(${prefix}_1秒待ちました) は動作する。

そしてforを使わない方がかっこいいと思っているので、mapを使った場合。

const asyncFunc = async (prefix: string): Promise<void> => {
  return new Promise(resolve => {
    setTimeout(() => {
      console.log(`${prefix}_1秒待ちました`)
      return resolve()
    }, 1000)
  })
}

const main = async () => {
  const prefixes = ['A', 'B', 'C', 'D', 'E']
  const asyncFuncs = prefixes.map(prefix => asyncFunc(prefix)) // 実行開始
  console.log('Promise.all前')
  await Promise.all(asyncFuncs).then(() => console.log('完了')) // すべてPromiseを返すまで待つ
  console.log('Promise.all後')
}

main()

実行するとどちらも下のように動く。

$ yarn run ts-node main.ts
yarn run v1.16.0
warning package.json: No license field
Promise.all前
A_1秒待ちました
B_1秒待ちました
C_1秒待ちました
D_1秒待ちました
E_1秒待ちました
完了
Promise.all後
✨  Done in 2.71s.