もう語り尽くされた感もあるのですが、async/awaitで複数のPromiseを待ち合わせる場合のやり方についてです。
Chrome 69のDevToolsのコンソールで動作確認を行いました。
3行で
-
Promise.all()
を使う方法があるよね - awaitの配列を作る方法もあるみたいなんだ
- おもしろいね(小並感)
Promise.all()をawaitする
筆者がよくやるのは、Promise.all()
をawaitする方法です。
async function hoge() {
const start = Date.now(); // 時間計測用
// sleep的なやつ
const p11 = new Promise(resolve => setTimeout(resolve, 1000));
const p12 = new Promise(resolve => setTimeout(resolve, 2000));
const p13 = new Promise(resolve => setTimeout(resolve, 3000));
// 結果を待ち合わせる
const [r11, r12, r13] = await Promise.all([p11, p12, p13]);
// 経過時間を表示
console.log("time", Date.now() - start);
}
hoge();
=> time 3005
逐次に実行されたら6秒かかる処理ですが、並行で実行されてくれたようで、3秒で終わっています。
p11〜p13の結果が出揃った時点で結果が出るので、待ち合わせをしたい場合には、これでよさそうです。
awaitの配列を作る
さて、こんな話を同僚の @kaminchu にしてみたところ、
const [r11, r12, r13] =[await p11, await p12, await p13];
でいけるかも・・・?
というコメントをいただきまして、「流石にそれは逐次で実行されるやろー」と思いながら試してみました。
async function fuga() {
const start = Date.now(); // 時間計測用
// sleep的なやつ
const p21 = new Promise(resolve => setTimeout(resolve, 1000));
const p22 = new Promise(resolve => setTimeout(resolve, 2000));
const p23 = new Promise(resolve => setTimeout(resolve, 3000));
// 結果を待ち合わせる
const [r21, r22, r23] = [await p21, await p22, await p23];
// 経過時間を表示
console.log("time", Date.now() - start);
}
fuga();
=> time 3003
並行処理になってる……!!!!
動いちゃった以上は疑いようがないですが、評価順が謎です。もともとそういう仕様なんでしょうけれども、意外でした。疑ってごめんよ……
両者の違い
記述量だったり見た目の違いというのはあるのですが、挙動としてはあまり違いがないので、好きな方を使えばよさそう、というのが正直なところです。
追記
と思っていましたが、Promise.all()
と[await p1, await p2...]
は全然違う挙動でした。new Promise()
の式と[await p1, await p2...]
を組み合わせると近い挙動にはなりますが、[await p1, await p2...]
という記法自体がPromise.all()
と同じ機能を持っているわけではありません。
コメント欄でご指摘いただきましたが、awaitを配列にするやり方は、
const p21 = new Promise(resolve => setTimeout(resolve, 1000));
const p22 = new Promise(resolve => setTimeout(resolve, 2000));
const p23 = new Promise(resolve => setTimeout(resolve, 3000));
の時点で並行処理が始まっているので、これだと
const p21 = new Promise(resolve => setTimeout(resolve, 1000));
const p22 = new Promise(resolve => setTimeout(resolve, 2000));
const p23 = new Promise(resolve => setTimeout(resolve, 3000));
const r21 = await p21;
const r22 = await p22;
const r23 = await p23;
とあまり変わりません。
筆者は Promise.all()
を使う感じになりそうです。
まとめ
async/awaitは奥が深いですね(小並感)