JavaScript | 「複数のAPIを並列処理 → 一部失敗時に安全に処理を続ける」を実例で比較(良いコード / 悪いコード)

JavaScript JavaScript
スポンサーリンク

これは「非同期処理を複数まとめて実行しつつ、一部が失敗しても全体を止めずに進める」という実践的なテーマです。
API連携やWebアプリで「部分的にデータ取得に失敗しても、取れる部分だけ表示したい」という場面で頻出します。


目標

複数の fetch(非同期処理)を並列で実行し、
一部が失敗してもプログラム全体を落とさず、成功した部分だけ処理を続ける。


基本の考え方

非同期処理をまとめて待つには:

await Promise.all([...])
JavaScript

を使うのが基本ですが、
👉 ひとつでも失敗(reject)すると全体がエラーになる のが難点。

そこで、落ちないようにするために:

  • Promise.allSettled()(すべての結果を「成功」「失敗」両方とも返す)
  • 各処理を try...catch でラップする

…という工夫をします。


❌ 悪い例:Promise.all() だけで並列実行

async function fetchDataBad() {
  try {
    const results = await Promise.all([
      fetch('https://example.com/api/user'),   // OK
      fetch('https://wrong.url/api/posts'),    // ❌ ここで失敗
      fetch('https://example.com/api/comments') // OK
    ]);

    // ここには到達しない(1つでも失敗すると全体がreject)
    const jsons = await Promise.all(results.map(r => r.json()));
    console.log('全データ:', jsons);

  } catch (err) {
    console.error('どれか1つでも失敗 → 全体エラー:', err.message);
  }
}

fetchDataBad();
JavaScript

問題点

  • 2番目のAPIが落ちた瞬間、残りもすべて中断される
  • 成功していたデータも取得できない。

✅ 良い例:Promise.allSettled() を使う

async function fetchDataGood() {
  const urls = [
    'https://example.com/api/user',
    'https://wrong.url/api/posts',   // ここは失敗
    'https://example.com/api/comments'
  ];

  const results = await Promise.allSettled(
    urls.map(url => fetch(url))
  );

  const successes = [];
  const failures = [];

  for (const [index, result] of results.entries()) {
    if (result.status === 'fulfilled') {
      successes.push(await result.value.json());
    } else {
      failures.push({ url: urls[index], error: result.reason });
    }
  }

  console.log('✅ 成功データ:', successes);
  console.log('⚠️ 失敗データ:', failures);
}

fetchDataGood();
JavaScript

出力イメージ

✅ 成功データ: [ {name:"Alice"}, {comment:"OK"} ]
⚠️ 失敗データ: [ {url:"https://wrong.url/api/posts", error: TypeError: ...} ]

ポイント

  • どれが成功/失敗かを「個別」に判定できる
  • 全体が止まらない
  • 成功した分だけで処理を進められる

応用版:個々の fetch に try…catch を仕込む

もう少し丁寧に「中身で安全に処理」する書き方もあります。

async function safeFetch(url) {
  try {
    const res = await fetch(url);
    if (!res.ok) throw new Error(`HTTP ${res.status}`);
    return await res.json();
  } catch (e) {
    return { error: true, message: e.message, url };
  }
}

async function fetchAllData() {
  const urls = [
    'https://example.com/api/user',
    'https://wrong.url/api/posts',
    'https://example.com/api/comments'
  ];

  const promises = urls.map(u => safeFetch(u));
  const results = await Promise.all(promises);

  const ok = results.filter(r => !r.error);
  const ng = results.filter(r => r.error);

  console.log('✅ 成功データ:', ok);
  console.log('⚠️ 失敗データ:', ng);
}

fetchAllData();
JavaScript

メリット

  • 1つの処理失敗で全体が止まらない
  • 成功・失敗をわかりやすく仕分けできる
  • Promise.allSettled() より柔軟に再利用できる

比較まとめ表

方法特徴向いているケース
Promise.all()1つでも失敗すると全体エラー全部のAPIが成功しないと意味がない場合
Promise.allSettled()成功・失敗を両方返すできるだけ多くの結果を集めたいとき
個別 try...catch柔軟に再利用できる、安全安定動作を最優先したいとき

実務でのコツ

  • 重要なデータ(例:ユーザー情報)は失敗したら再試行、
    サブデータ(例:コメント数)は失敗してもスルーなど、優先度を分ける
  • 成功・失敗ログをわかりやすく残しておく。
  • 大量のリクエストを同時に投げすぎない(API制限注意)。

まとめ(初心者が押さえるべきポイント)

覚えるべきこと説明
Promise.all() は「全成功前提」1つでも落ちると全部落ちる
Promise.allSettled() は「全結果を返す」一部失敗でもOK
個別 try...catch or safeFetch 関数再利用・安全性重視
「一部成功でも続行する」設計実務で超重要

タイトルとURLをコピーしました