catchを使ったエラーハンドリングの基本と応用をわかりやすく解説

スポンサーリンク
スポンサーリンク
amazon
スマイルSALE
--:--:--
~
ad. 価格範囲を指定して商品を探せます

catchの概要

エラーハンドリング JavaScript予約語

catch

概要 catchはJavaScriptで例外処理を行うための構文で、try...catchブロックの一部として使用されます。
tryブロック内で発生したエラーをキャッチし、適切に処理するために使用されます。

わかりやすく説明 catchは「プログラムの実行中に何か問題(エラー)が起きたら、システムを止めずにここで安全に回収して処理する」というセーフティネットの仕組みを提供します。

  • 例外処理により、予期せぬエラーが起きてもプログラムの実行を中断せずに継続できます。
  • エラーの詳細情報を利用して、原因を特定したりデバッグしたりできます。
  • エラーに応じた適切な画面表示や、ユーザーへのレスポンスを返すことが可能です。

catchの基本的な使い方

JavaScriptでは、定義されていない変数を呼び出すなどの問題が発生すると、通常はプログラムがその時点で強制終了してしまいます。
そこで try...catch 構文を使い、エラーが起きそうな処理を try で囲むことで、万が一エラーが発生しても catch ブロックへ処理を逃がすことができるようになります。
以下は、try...catch を使った最も基本的なエラー捕捉の例です。

// 基本的なtry...catchの使用例
try {
    const result = 10 / 0; // JavaScriptでは0で割ってもエラーにならず「Infinity(無限大)」が返ります
    console.log(result);

    // 存在しない(未定義の)変数を参照するため、ここでエラーが発生します
    const undefinedVariable = undefinedValue; 
    
    // エラーが発生した時点で処理がcatchへ飛ぶため、この下の行は実行されません
    console.log("ここは実行されません");
} catch (error) {
    // 引数(error)に発生したエラーのオブジェクトが自動的に渡されます
    console.error("エラーをキャッチしました:", error.message); // エラーメッセージを出力
}
  • tryブロック内でエラーが発生した瞬間に、それ以降の処理をスキップして即座にcatchブロックへと処理が移ります。
    これにより、アプリ全体のクラッシュを防ぐことができます。
  • errorオブジェクトには、エラーの名前(name)や具体的なメッセージ(message)などの詳細情報が格納されており、トラブルシューティングに役立ちます。

エラーに応じた処理

一口にエラーと言っても、文字の打ち間違いによる構文エラー(SyntaxError)や、型が違うことによるエラー(TypeError)など、様々な種類があります。
catch ブロックの中では、発生したエラーの種類(クラス)を instanceof を使って判別し、それぞれに合わせた個別のエラーハンドリングを行うことができます。

// エラータイプによる処理分岐
try {
    // 構文として間違っている無効なJSON文字列をパースしようとします
    JSON.parse("invalid JSON"); 
} catch (error) {
    // errorが「構文エラー(SyntaxError)」の仲間であるかを判定します
    if (error instanceof SyntaxError) {
        console.error("JSONの構文に間違いがあります:", error.message);
    } else if (error instanceof TypeError) {
        console.error("データの型が正しくありません:", error.message);
    } else {
        console.error("その他の予期しないエラー:", error.message);
    }
}
  • error instanceof エラーの型を使用することで、エラーの正体を細かく見極めることができます。
    「ユーザーの入力ミスなら優しい警告を出す」「深刻なシステムエラーなら管理者に通知する」といった柔軟な実装が可能になります。
  • エラーに応じた異なる処理を実装可能です。

非同期コードでのエラーハンドリング

APIからデータを取得するような非同期処理では、エラーをキャッチする方法が2通りあります。
最新の async/await 構文を使う場合は、通常の同期処理と同じように try...catch で囲むだけで済みますが、従来の Promise チェーンを繋ぐ場合は .catch() メソッドを使ってエラーを待ち受ける必要があります。

// 1. async/await関数でのエラーハンドリング(直感的でおすすめ)
async function fetchData() {
    try {
        const response = await fetch("https://invalid.url"); // 無効なURLでネットワークエラー発生
        const data = await response.json();
        console.log(data);
    } catch (error) {
        console.error("async/await内でのデータ取得エラー:", error.message);
    }
}

fetchData();

// 2. Promiseチェーンでのエラーハンドリング(昔ながらの書き方)
fetch("https://invalid.url")
    .then(response => response.json())
    .catch(error => {
        // チェーンのどこかでエラーが起きると、一番最後の.catch()へ滑り込んできます
        console.error("Promiseチェーンでのエラー:", error.message);
    });
  • async/await構文では、非同期処理であっても見慣れたtry...catchの形に統一できるため、コードの可読性が格段に上がります。
  • Promiseをそのまま扱う場合は、末尾に必ず.catchメソッドを連結させておくことが、エラーを見落とさないための重要なルールとなります。

注意点

  • エラーの発生箇所: tryブロックの中に書かれたコードだけがcatchの保護対象になります。
    tryブロックの外側で発生したエラーはまったくキャッチできないため、エラーの予測される範囲を正しく囲む必要があります。

    // ❌ NGな例:tryブロックの外側でエラーが起きているため、catchを通り過ぎてクラッシュします
    const baseData = undefinedValue; // 🛑 ここでエラー発生!tryの外なので守られません
    
    try {
        console.log(baseData);
    } catch (error) {
        console.error("キャッチできません:", error.message);
    }
    
  • グローバルエラーのキャッチ: 個別の try...catch をすり抜けてしまった未知のエラーは、ブラウザ環境では window.onerror、Node.js環境では process.on('uncaughtException') を使って、アプリ全体で最後にまとめて回収することができます。
  • エラーの意図的なスロー: 「パスワードが短すぎる」といった、プログラムのバグではないけれどシステム的に処理を中断させたい場合は、throw キーワードを使って自らエラーを発生させ、意図的に catch ブロックへ処理をジャンプさせることができます。

よくある質問

Q: catchでエラーをキャッチしないケースはありますか?
A: はい、あります。
通常の try...catch は「同期的な処理」のエラーしか監視できません。
try ブロックの内部であっても、setTimeout の中などの非同期処理で発生したエラーは、時間差で実行されるため catch をすり抜けてしまいます。
非同期処理のエラーは、前述した async/await や .catch() メソッドを使って正しくハンドリングする必要があります。

// ❌ NGな例:setTimeout内の非同期エラーは、このtry...catchでは捕まえられません
try {
    setTimeout(() => {
        const errorVal = undefinedValue; // 🛑 1秒後にここでエラーが起きますが、すでにtryの監視は終わっています
    }, 1000);
} catch (error) {
    console.error("ここには来ません(キャッチ失敗)");
}
Q: エラーを再スロー(もう一度発生)させるにはどうすればいいですか?
A: catch ブロックの中で再度 throw キーワードを使用することで、一度捕まえたエラーをさらに外側の例外処理に向けて「再スロー(再投げ)」することができます。
「エラーのログだけをここで記録し、実際の画面エラー処理は呼び出し元の親関数に任せたい」という場合に非常によく使われるテクニックです。

// エラーを再スローする例
function processData() {
    try {
        throw new Error("データ破損");
    } catch (error) {
        console.warn("(子)ここでログを記録します");
        throw error; // ❗ エラーを再スローして外側に丸投げします
    }
}

try {
    processData();
} catch (error) {
    console.error("(親)最終的にここでエラーを解決します:", error.message);
}
Q: 非同期関数でエラーが発生した場合の推奨されるハンドリング方法は?
A: 現代のJavaScript開発では、コードをスマートに保つために async/await と try...catch 構文を組み合わせる方法が最も推奨されています。
複数の非同期処理が複雑に絡む場合や、古いコードのメンテナンスでは、Promiseチェーンの末尾で .catch() メソッドを使って処理する方法も合わせて活用してください。

まとめ

catchは、JavaScriptで例外処理を行い、エラーに応じた適切なレスポンスやデバッグを可能にする重要な機能です。

  • 例外処理を正しく組み込むことで、バグが起きてもシステムを中断せずに安全に稼働を続行できます。
  • instanceof を使ってエラータイプを細かく判別し、状況に応じたユーザーへの案内や処理をスマートに実装可能です。
  • 同期処理だけでなく、非同期コードでも async/await や .catch() を活用して、予期せぬ通信エラーに強い信頼性の高いプログラムを実現しましょう。