Help us understand the problem. What is going on with this article?

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

More than 1 year has passed since last update.

もう語り尽くされた感もあるのですが、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は奥が深いですね(小並感)

Why not register and get more from Qiita?
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
Comments
No comments
Sign up for free and join this conversation.
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
  1. We will deliver articles that match you
    By following users and tags, you can catch up information on technical fields that you are interested in as a whole
  2. you can read useful information later efficiently
    By "stocking" the articles you like, you can search right away
ユーザーは見つかりませんでした