30.

【PHP】try catchで全てのエラーを拾う方法

編集
この記事の要点
  • JavaScript で全てのエラーを捕捉する方法
  • try/catch: 同期コード + await した非同期コード
  • Promise.catch(): 非同期チェーンのエラー
  • window.onerror / window.addEventListener("error", ...): 未捕捉のエラー(グローバル)
  • window.addEventListener("unhandledrejection", ...): 捕捉漏れの Promise エラー

 

try / catch(同期 + await)

try {
    const data = JSON.parse(invalidJson);
} catch (error) {
    console.error("エラー:", error.message);
}

// async / await の場合
async function fetchData() {
    try {
        const res = await fetch("/api/data");
        if (!res.ok) throw new Error(`HTTP ${res.status}`);
        return await res.json();
    } catch (error) {
        console.error("失敗:", error);
        return null;
    }
}

finally で後片付け

async function operation() {
    let loading = true;
    try {
        const data = await fetch("/api");
        return data;
    } catch (error) {
        console.error(error);
        return null;
    } finally {
        loading = false;  // 必ず実行される
        console.log("完了");
    }
}

Promise の catch

fetch("/api/data")
    .then(res => res.json())
    .then(data => console.log(data))
    .catch(error => console.error("失敗:", error))
    .finally(() => console.log("完了"));

// 複数 Promise
Promise.all([fetch("/api/a"), fetch("/api/b")])
    .then(([a, b]) => { ... })
    .catch(error => console.error("どれかが失敗:", error));

// 並列で個別エラー処理
Promise.allSettled([fetch("/api/a"), fetch("/api/b")])
    .then(results => {
        results.forEach(r => {
            if (r.status === "fulfilled") {
                console.log("成功:", r.value);
            } else {
                console.error("失敗:", r.reason);
            }
        });
    });

グローバルなエラーハンドラ

① window.onerror(同期エラー + リソース読み込み)

// 古典的な方法
window.onerror = function (message, source, lineno, colno, error) {
    console.error("グローバルエラー:", { message, source, lineno, colno, error });
    // サーバに送信
    fetch("/api/log/error", {
        method: "POST",
        body: JSON.stringify({ message, source, lineno, colno, stack: error?.stack })
    });
    return true;  // true を返すとブラウザのデフォルトエラー処理を抑止
};

// addEventListener 版(複数ハンドラを登録可能)
window.addEventListener("error", (event) => {
    console.error("グローバルエラー:", event.error);
    event.preventDefault();  // ブラウザのコンソール出力を抑止
});

② unhandledrejection(Promise の捕捉漏れ)

// .catch() を書き忘れた Promise を拾う
window.addEventListener("unhandledrejection", (event) => {
    console.error("未処理の Promise エラー:", event.reason);
    event.preventDefault();
});

// 発生例
async function bad() {
    await fetch("/invalid");  // 404 → .catch() なし
    JSON.parse("invalid");    // SyntaxError
}
bad();  // ← unhandledrejection が発火

③ リソース読み込みエラー(img, script, link)

// img や script の load エラーは bubble しない
// → addEventListener で capture: true にする
window.addEventListener("error", (event) => {
    if (event.target !== window) {
        // リソースエラー (img の 404 等)
        console.error("リソース読み込み失敗:", event.target.src || event.target.href);
    }
}, true);  // ← capture フェーズで拾う

React のエラーバウンダリ

class ErrorBoundary extends React.Component {
    state = { hasError: false };

    static getDerivedStateFromError(error) {
        return { hasError: true };
    }

    componentDidCatch(error, info) {
        console.error("React error:", error, info);
        // サーバ送信
    }

    render() {
        if (this.state.hasError) {
            return 

エラーが発生しました

; } return this.props.children; } } // 使い方

Vue.js のエラーハンドラ

// Vue 3
const app = createApp(App);
app.config.errorHandler = (err, instance, info) => {
    console.error("Vue error:", err, info);
    // info: 'render', 'mounted hook', etc.
};

// Vue 2
Vue.config.errorHandler = function (err, vm, info) {
    console.error("Vue error:", err, info);
};

// コンポーネント単位
export default {
    errorCaptured(err, vm, info) {
        console.error("Captured:", err);
        return false;  // false なら親に伝播しない
    }
};

カスタム Error クラス

class ValidationError extends Error {
    constructor(message, field) {
        super(message);
        this.name = "ValidationError";
        this.field = field;
    }
}

class NetworkError extends Error {
    constructor(message, statusCode) {
        super(message);
        this.name = "NetworkError";
        this.statusCode = statusCode;
    }
}

// 使用
try {
    if (!email) throw new ValidationError("メール必須", "email");
    if (!response.ok) throw new NetworkError("API 失敗", response.status);
} catch (error) {
    if (error instanceof ValidationError) {
        showFieldError(error.field, error.message);
    } else if (error instanceof NetworkError) {
        showNetworkError(error.statusCode);
    } else {
        console.error("予期しないエラー:", error);
    }
}

エラーログをサーバ送信

function logErrorToServer(error, context = {}) {
    fetch("/api/log/error", {
        method: "POST",
        headers: { "Content-Type": "application/json" },
        body: JSON.stringify({
            message: error.message,
            stack: error.stack,
            url: location.href,
            userAgent: navigator.userAgent,
            timestamp: new Date().toISOString(),
            ...context
        })
    }).catch(() => { /* ログ送信失敗は無視 */ });
}

// グローバルハンドラから呼ぶ
window.addEventListener("error", (e) => logErrorToServer(e.error || new Error(e.message)));
window.addEventListener("unhandledrejection", (e) => logErrorToServer(e.reason));

エラー監視ツール

本格運用なら専用サービスを使う:

  • Sentry: 無料枠あり、ベスト
  • Rollbar
  • Datadog RUM
  • New Relic Browser
// Sentry の例
import * as Sentry from "@sentry/browser";

Sentry.init({
    dsn: "https://...@sentry.io/...",
    environment: "production",
    tracesSampleRate: 0.1
});

// 自動で window.onerror / unhandledrejection を捕捉
// 手動送信
Sentry.captureException(new Error("カスタムエラー"));
Sentry.captureMessage("情報メッセージ", "info");

注意点

  • try/catch は同期と await のみ: Promise の .then() 内のエラーは届かない
  • 非同期コールバック: setTimeout(fn, 0) 内のエラーは外の try/catch で拾えない
  • イベントリスナー内のエラー: ハンドラ内で try/catch するか、グローバル onerror に任せる
  • cross-origin script のエラー: 詳細情報が "Script error" としか出ない → crossorigin="anonymous" 属性 + サーバ CORS 設定

関連記事

編集
Post Share
子ページ

子ページはありません

同階層のページ
  1. 基本事項
  2. HTMLへの埋め込み
  3. 変数
  4. 可変変数
  5. 定数
  6. データ型
  7. キャスト
  8. エスケープ文字
  9. 配列
  10. 演算子
  11. 代入の際の注意点
  12. 条件分岐
  13. 繰り返し処理
  14. クラスとインスタンス
  15. コンストラクタ
  16. 関数
  17. スーパーグローバル変数
  18. スコープ
  19. staticについて
  20. yieldについて
  21. ファイルのアップロード方法
  22. DB接続方法
  23. SQL実行方法
  24. カプセル化の具体例
  25. 継承の構文
  26. オーバーライド
  27. ポリモーフィズム(多様性)の具体例
  28. 抽象クラス・メソッドの構文と具体例
  29. GET通信
  30. try catchで全てのエラーを拾う方法