🤩

JavaScriptにおける Promise.all の並列処理とパフォーマンス最適化

2025/02/20に公開

はじめに

JavaScriptの非同期処理を適切に扱うことはパフォーマンス向上の鍵となります。本記事では、Promise.all を活用した並列処理について解説し、どのようにして API リクエストのパフォーマンスを改善できるのかを紹介します。

Promise.all の基本

通常、await を使った非同期処理は逐次実行されるため、複数のリクエストを順番に処理すると全体の実行時間が長くなってしまいます。

そのため、データ間に依存関係がない場合は、並列にデータ取得を行うことでパフォーマンスが効率的になります。

例えば、以下のコードでは getUserProfile の処理が完了してから getUserPosts が実行されるため、両者の合計時間がかかってしまいます。

const userProfile = await getUserProfile(userId);
const userPosts = await getUserPosts(userId);

これを Promise.all を使うことで、両方のリクエストを並列して実行し、パフォーマンスを向上させることができます。

Promise.all を使った並列処理

以下のように Promise.all を使用することで、getUserProfilegetUserPosts を同時に実行し、両者の完了を待つことができます。

  const [profile, posts] = await Promise.all([
    getUserProfile(userId),
    getUserPosts(userId),
  ]);

これにより、個々の処理を逐次実行するよりも高速にデータを取得できます。

実行時間の比較

  • 逐次実行 (順番に実行): getUserProfile に 500ms、getUserPosts に 800ms かかる場合、合計 1300ms かかる。
  • 並列実行 (Promise.all): どちらも同時に開始されるため、最大時間である 800ms で完了。

つまり、Promise.all を使用することで処理時間を短縮できます。

以下の画像は、Next.jsの公式ドキュメントにあるデータ取得の逐次実行と並列実行によるパフォーマンスのイメージ図です。

Promise.all の注意点

Promise.all を使う際には、以下の点に注意が必要です。

  1. いずれかの処理が失敗すると全体が失敗する

    • Promise.all はすべてのプロミスが成功するまで待機しますが、一つでもエラーが発生すると即座に catch に入り、他のプロミスの結果を取得できません。
    • 対策: Promise.allSettled を使用することで、すべての処理の結果を取得可能。
    const results = await Promise.allSettled([
      getUserProfile(userId),
      getUserPosts(userId),
    ]);
    
    results.forEach((result) => {
      if (result.status === "fulfilled") {
        console.log("Success:", result.value);
      } else {
        console.error("Error:", result.reason);
      }
    });
    
  2. API に負荷をかけすぎないようにする

    • Promise.all はすべての処理を並列実行するため、一度に大量のリクエストを送るとサーバーに負荷をかける可能性があります。
    • 対策: p-limit などのライブラリを使用して同時リクエスト数を制御する。

まとめ

Promise.all を活用することで、複数の非同期処理を並列実行し、パフォーマンスを大幅に向上させることができます。

本記事が Promise.all を活用した効率的な非同期処理の実装に役立てば幸いです。

Discussion