JavaScript Tips | ログ・デバッグ・エラー処理:Promiseエラーを捕捉する

JavaScript JavaScript
スポンサーリンク
スポンサーリンク

Promiseエラー捕捉は「非同期処理の落とし穴を確実に拾い上げるための必須テクニック」

Promise は便利ですが、初心者が必ずつまずくポイントがあります。

  • try/catch では Promise のエラーを捕捉できない場合がある
  • .catch() を書き忘れると Unhandled Rejection(未処理拒否) が発生する
  • 非同期処理の中で発生した例外が 静かに消える
  • 本番環境で原因不明のエラーが発生し、ログが残らない

業務システムでは、Promise エラーを確実に捕捉し、 ログに残し、必要なら監視ツールに送信する仕組みが必須です。

ここでは、ステップバイステップで Promise エラー捕捉の考え方 → 実装 → 強化 → 業務テンプレート までを丁寧に解説します。

Promise エラーが try/catch で捕捉できない理由を理解する(最重要)

例:try/catch が効かないケース

try {
  Promise.reject(new Error("API失敗"));
} catch (e) {
  console.log("捕捉できない");
}
JavaScript

これは catch に入らない ため、エラーが消えます。

理由は、Promise のエラーは 非同期的に発生するため、 try/catch の同期的な例外捕捉では拾えないからです。

ステップ1:Promise のエラーを .catch() で捕捉する(基本)

fetch("/api/user")
  .then(res => res.json())
  .catch(e => {
    console.error("Promiseエラー:", e);
  });
JavaScript

重要ポイント

  • .catch() を書き忘れると Unhandled Rejection になる
  • Promise チェーンの最後に必ず .catch() を付ける習慣が重要

ステップ2:async/await のエラーは try/catch で捕捉できる

async function run() {
  try {
    const res = await fetch("/api/user");
    return await res.json();
  } catch (e) {
    console.error("async/await エラー:", e);
  }
}
JavaScript

重要ポイント

  • async/await は Promise を「同期的に扱える」ため try/catch が効く
  • ただし、await を書き忘れると捕捉できない

ステップ3:Promise エラーを共通化する(業務で必須)

毎回 .catch() を書くのは非効率なので、 Promise を安全に実行するユーティリティを作ります。

async function safePromise(promise, context = "") {
  try {
    const result = await promise;
    return { ok: true, value: result };
  } catch (e) {
    console.error(`[ERROR] [${context}]`, e);
    return { ok: false, error: e };
  }
}
JavaScript

使用例

const res = await safePromise(fetch("/api/user"), "UserAPI");

if (!res.ok) return;
console.log(res.value);
JavaScript

ステップ4:Promise の未処理拒否(Unhandled Rejection)を捕捉する

Promise の .catch() を書き忘れると発生するエラーです。

ブラウザの場合

window.onunhandledrejection = function(event) {
  console.error("[UNHANDLED REJECTION]", event.reason);
};
JavaScript

Node.js の場合

process.on("unhandledRejection", (reason) => {
  console.error("[UNHANDLED REJECTION]", reason);
});
JavaScript

重要ポイント

  • 本番環境では必ず設定する
  • これがないと「静かに消えるエラー」が発生する

ステップ5:Promise エラーを整形して読みやすくする

function formatPromiseError(e) {
  return {
    name: e?.name,
    message: e?.message,
    stack: e?.stack,
  };
}
JavaScript

ステップ6:Promise エラーを共通 Logger に流す

function logPromiseError(e, context) {
  Logger.error(formatPromiseError(e), context);
}
JavaScript

ステップ7:業務で使える Promise エラー捕捉ユーティリティ(完成版)

export const PromiseErrorUtil = {
  format(e) {
    return {
      name: e?.name,
      message: e?.message,
      stack: e?.stack,
      ...Object.keys(e || {}).reduce((acc, key) => {
        acc[key] = e[key];
        return acc;
      }, {}),
    };
  },

  async run(promise, context = "") {
    try {
      const value = await promise;
      return { ok: true, value };
    } catch (e) {
      Logger.error(this.format(e), context);
      return { ok: false, error: this.format(e) };
    }
  },

  initGlobalHandler() {
    if (typeof window !== "undefined") {
      window.onunhandledrejection = (event) => {
        Logger.error(this.format(event.reason), "UnhandledRejection");
      };
    }

    if (typeof process !== "undefined") {
      process.on("unhandledRejection", (reason) => {
        Logger.error(this.format(reason), "UnhandledRejection");
      });
    }
  },
};
JavaScript

ステップ8:業務での活用例

API 呼び出し

const res = await PromiseErrorUtil.run(fetch("/api/user"), "UserAPI");
JavaScript

DB 操作

const result = await PromiseErrorUtil.run(db.query("SELECT * FROM users"), "DBQuery");
JavaScript

バッチ処理

const batch = await PromiseErrorUtil.run(runBatch(), "SalesBatch");
JavaScript

グローバルハンドラの初期化

PromiseErrorUtil.initGlobalHandler();
JavaScript

深掘り:Promise エラー捕捉が重要な理由

1. 非同期エラーは try/catch では拾えない場合がある

Promise の特性を理解しないと、エラーが消えます。

2. Unhandled Rejection は本番で致命的

静かに消えるため、障害調査が困難になります。

3. 監視ツールとの連携が容易になる

整形された Promise エラーは外部サービスに送信しやすいです。

4. エラー処理の統一でコードが読みやすくなる

業務ロジックがシンプルになり、保守性が向上します。

まとめ:Promise エラー捕捉は「非同期処理の安全性を守るための必須技術」

Promise エラー捕捉を正しく扱うことで、次のメリットが得られます。

  • 非同期エラーを確実に捕捉できる
  • Unhandled Rejection を防げる
  • ログ形式が統一される
  • 障害調査が高速化する
  • 監視ツールとの連携が容易になる

Promise は便利ですが、 エラー捕捉を正しく設計しないと危険な落とし穴になります。

共通 Logger や try/catch 共通化と組み合わせることで、 業務システムの安定性が大きく向上します。

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