JavaScript | 「fetch+async+finally(後処理付き)」を実例で比較(良いコード / 悪いコード)

JavaScript JavaScript
スポンサーリンク

ここでは、「fetch × async/await × finally」 を組み合わせて、
「通信成功・失敗どちらでも後処理を確実に実行する」コードを、
初心者でも理解できるようにステップごとに解説します。


ゴール

✅ 非同期処理での try...catch...finally の流れを理解する
✅ 通信が成功しても失敗しても「後片付け(finally)」が必ず動くことを確認する


基本構造(復習)

try {
  // ① 通常の処理
} catch (err) {
  // ② エラーが起きたときに実行される
} finally {
  // ③ 成功しても失敗しても必ず実行される(後処理)
}

実例1:fetch + async/await + finally

async function fetchUserData() {
  console.log('--- 通信開始 ---');

  try {
    const response = await fetch('https://api.example.com/user/123');
    
    if (!response.ok) {
      throw new Error(`HTTPエラー: ${response.status}`);
    }

    const data = await response.json();
    console.log('✅ データ取得成功:', data);

  } catch (err) {
    console.error('❌ エラー発生:', err.message);

  } finally {
    console.log('🧹 後処理: ローディング表示を消す、接続を閉じるなど');
  }

  console.log('--- 通信終了 ---');
}

fetchUserData();
JavaScript

実行の流れ

✅ 通信成功時

--- 通信開始 ---
✅ データ取得成功: { ... }
🧹 後処理: ローディング表示を消す、接続を閉じるなど
--- 通信終了 ---

❌ 通信失敗時(例: URLが間違い)

--- 通信開始 ---
❌ エラー発生: Failed to fetch
🧹 後処理: ローディング表示を消す、接続を閉じるなど
--- 通信終了 ---

👉 成功でも失敗でも finally は必ず実行される


実務的な応用(UI付きシミュレーション)

たとえば「通信中はローディング表示、終わったら消す」というような処理。

async function loadData() {
  const loader = document.querySelector('#loader');
  loader.style.display = 'block'; // ローディング表示ON

  try {
    const response = await fetch('https://api.example.com/data');
    if (!response.ok) throw new Error('サーバーエラー');
    
    const result = await response.json();
    console.log('データ取得:', result);

  } catch (err) {
    console.error('通信エラー:', err.message);

  } finally {
    loader.style.display = 'none'; // 成否に関係なく非表示
    console.log('ローディング終了');
  }
}
JavaScript

💬 解説:

  • 通信成功 → データを使う
  • 通信失敗 → エラーメッセージ表示
  • finally → 「ローディング中」UIをOFFにする
     (成功しても失敗しても“後片付け”は必ず必要)

補足:return や throw があっても finally は動く

async function testFinally() {
  try {
    console.log('try内');
    return 'done';
  } finally {
    console.log('finallyは必ず実行される');
  }
}

testFinally();
JavaScript

出力:

try内
finallyは必ず実行される

return の前でも finally は必ず動く!


🚫 悪い例:finally を忘れてリソースを放置

async function badExample() {
  const conn = openDatabaseConnection();
  const data = await fetchData(conn); // ← ここでエラーになることも
  conn.close(); // ← エラーが起きると実行されない!
}
JavaScript

→ 途中で例外が出ると conn.close() が呼ばれず、「接続が閉じられない」などのバグに。


✅ 良い例:finally で安全に後処理

async function goodExample() {
  const conn = openDatabaseConnection();

  try {
    const data = await fetchData(conn);
    console.log('取得:', data);
  } catch (e) {
    console.error('失敗:', e.message);
  } finally {
    conn.close(); // ← 必ず実行される
  }
}
JavaScript

練習問題

問題1:
次のコードは「ローディング中」を消し忘れています。finally を使って直してください。

async function getData() {
  showLoading(); // ローディング表示
  const response = await fetch('https://wrong.url');
  const data = await response.json();
  hideLoading(); // ← 通信エラー時に実行されない!
}
JavaScript

解答例:

async function getData() {
  showLoading();

  try {
    const response = await fetch('https://wrong.url');
    const data = await response.json();
    console.log('成功:', data);
  } catch (e) {
    console.error('失敗:', e.message);
  } finally {
    hideLoading(); // ← 成否関係なく必ず実行
  }
}
JavaScript

まとめ:finally の使いどころ

状況finally の使い道
ローディング表示を消すUI の後片付け
ファイルを閉じるリソース解放
データベース接続を切るサーバー側の安定運用
一時変数やフラグのリセット状態を元に戻す

まとめ(ポイント整理)

  • finally成功・失敗・return の有無に関係なく必ず実行される。
  • fetch のような非同期処理では「UIの後片付け」や「接続の終了」に最適。
  • 例外が起きても「後始末」が安全にできるように、try/catch/finally は3点セットで使うのがベスト。

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