LoginSignup
150
112

More than 5 years have passed since last update.

async/await で複数の非同期処理を待つときに注意したいこと

Last updated at Posted at 2018-08-13

本投稿のサンプルコードを GitHub に用意しました。
im36-123/multiple_await | GitHub

概要

async/await を使うとで非同期処理を同期処理のように記述できますが、複数の非同期処理を待つときに気をつけたいことを紹介します。
複数のリクエスト送信して、それらのレスポンスからページを構成するときなどに役立つかもしれません。

今回は Fetch API を使って複数のリクエストを送信する場合を考えてみます。

普通に async/await を使う

まずは、ひとつだけリクエストを送信する場合を考えてみます。

ひとつだけリクエストを送信する
function get(url) {
  return fetch(url);
}

async function fn() {
  const res = await get(`https://hoge/api`);
  console.log(res);
}

fn();

fn() が実行されると、 https://hoge/api へリクエストを送信します。
レスポンスがあるまで、 fn() 内の処理は停止します。
特に問題ありませんね。

次は本題の複数のリクエストを待つ場合を見てみましょう

複数のリクエストを待つ

それでは2つ以上のリクエストを送信するときを考えてみます。

良くない書き方

先程のコードのリクエストを送信する部分を2つにしました(実際は for文などで loop させるかと思います。)。

良くないawait
function get(url) {
  return fetch(url);
}

async function fn() {
  const res1 = await get(`https://hoge/api`);
  const res2 = await get(`https://fuga/api`);
  console.log(res1);
  console.log(res2);
}

fn();

こちらのコードは問題なく動作しますが、パフォーマンスが落ちてしまいます。
というのも、res1 に結果が代入されるまで fn() 内の処理が止まってしまうためです。

developer tool の Network タブを見てみると、確かに1つ目のリクエスト結果の後に、2つ目のリクエストが送信されています。
image.png
(※ 上図では Qiita の api にリクエストを送信しています。)

良い書き方

res1 の結果が res2 のリクエストに影響しない場合は、次のように複数のリクエストが並列して処理されるようにします。

先程のコードを修正して、2つのリクエストが並列して処理されるようにしました。
また、 Promise.all を使ってすべてのリクエスト結果の返却を待ちましょう。

良いawait
function get(url) {
  return fetch(url);
}

async function fn() {
  const results = [];
  const urls = ['https://hoge/api', 'https://fuga/api'];
  for (const url of urls) {
    results.push(get(url));
  }
  console.log(await Promise.all(results));
}

fn();

こちらも developer tool の Network タブから確認してみましょう。
image.png

今回は、2つのリクエストが並行して処理されているのがわかります。

まとめ

業務で async/await を使っているときに ESLint に注意されたので書きました。

追記

@41semicolon さんよりコメントをいただきました…!!
fn() に関してですがコメントで頂いた下記のコードの方がスマートで素敵です。

async function fn() {
  const urls = ['https://hoge/api', 'https://fuga/api'];
  console.log(await Promise.all(urls.map(get)));
}

呼び出し側で await するなどのときはこちら。

fn = (urls) => Promise.all(urls.map(get))

詳しくはコメントを参照お願いします。

参考

no-await-in-loop - Rules - ESLint - Pluggable JavaScript linter
async function - JavaScript | MDN
await - JavaScript | MDN

150
112
2

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
150
112