JavaScript

async/awaitでPromiseの待ち合わせを行う

もう語り尽くされた感もあるのですが、async/awaitで複数のPromiseを待ち合わせる場合のやり方についてです。

Chrome 69のDevToolsのコンソールで動作確認を行いました。


3行で



  • Promise.all() を使う方法があるよね

  • awaitの配列を作る方法もあるみたいなんだ

  • おもしろいね(小並感)


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];

でいけるかも・・・?


というコメントをいただきまして、「流石にそれは逐次で実行されるやろー」と思いながら試してみました。


awaitの配列を作る方式

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は奥が深いですね(小並感)