こんにちはみなさん
昨日ちょっとPromise.all
の挙動で議論があったので、挙動をメモっておこうかなと思いました。まあ、仕様を読み込めばわかるやろ!って話なんだろうけど、手っ取り早くどうなるんだっけ?ってのを思い出すコストがめんどいんです。
Promise.all
Promise.all
は、引数に非同期関数(Promise)の配列をとって、それぞれを同時に実行してその結果を返すものです。
const timeout = async (time) => {
console.log(`${time} start`)
await new Promise(res => setTimeout(res, time))
console.log(`${time} end`)
return time
}
Promise.all([
timeout(500),
timeout(300),
timeout(100)
]).then(res => console.log(res))
timeout
は指定された時間の待機時間を挟んでコンソールログを出力し、入力した時間を返すだけの非同期関数です。
こいつを実行すると、こんなのが返ります
# node promiseAll.js
500 start
300 start
100 start
100 end
300 end
500 end
[ 500, 300, 100 ]
Promise.all
を使うと、登録されたすべての処理が完了してから、それぞれの結果を配列で取得することができます。また、登録された処理がそれぞれ同時に走っています。
複数の非同期処理の結果を使いたい場合のPromise.all
複数の非同期処理の結果を使いたい場合、Promise.allがパフォーマンスの向上に役に立ちます。
例えば以下の処理を見てみます。
const timeout = async (time) => {
console.log(`${time} start`)
await new Promise(res => setTimeout(res, time))
console.log(`${time} end`)
return time
}
const all = async () => {
a = await timeout(500)
b = await timeout(300)
c = await timeout(100)
console.log([a, b, c])
}
all()
各非同期処理の結果を変数に格納しているわけですが、この結果は以下の通りです。
# node async_res.js
500 start
500 end
300 start
300 end
100 start
100 end
[ 500, 300, 100 ]
各非同期処理が終わらないと次の処理に移っていないことがわかります。
せっかくの非同期処理ですが、これでは最終結果が出るまで余計に時間がかかります。
こんな時にPromise.allを使います。
const timeout = async (time) => {
console.log(`${time} start`)
await new Promise(res => setTimeout(res, time))
console.log(`${time} end`)
return time
}
const all = async () => {
console.log('all start')
const [a, b, c] = await Promise.all([
timeout(500),
timeout(300),
timeout(100)
])
console.log([a, b, c])
console.log('all end')
}
all()
こいつを実行すると
# node timeout_all.js
all start
500 start
300 start
100 start
100 end
300 end
500 end
[ 500, 300, 100 ]
all end
3つの非同期処理が全部同時に実行され、その結果がa, b, cに分割代入されている感じですね。
通信などの非同期処理が複数ある場合は、Promise.all使っちゃうのが楽ですね。
まとめ
Promise.allの挙動を復習してみました。
いや、PHPばかり触っていたので、JSの非同期処理の流れとか、忘れちゃうんですよね。
今回は軽めにこんなところです。