JavaScriptでの隠された宝石: error.cause
Grace Collins
Solutions Engineer · Leapcell

デバッグの課題
デバッグにおける最大の課題は何でしょうか?その一つは間違いなく、エラーの発生源を追跡することです。
次のシナリオを想像してください。
const func = () => { doSth('A'); doSth('B'); };
func
がエラーをスローした場合、エラーがどのステップで発生したかをどのように特定しますか?それはdoSth('A')
、doSth('B')
、またはfunc
自体のいずれが原因でしょうか?明らかに、エラーには十分なコンテキストがありません。
一般的な解決策
この問題に対処するための一般的なアプローチは次のようになります。
const func = () => { try { doSth('A'); } catch (error) { throw new Error('Aからのエラー', error); } try { doSth('B'); } catch (error) { throw new Error('Bからのエラー', error); } };
このアプローチを使用すると、エラーの発生源をより簡単に見つけることができます。ただし、この解決策にはいくつかの制限があります。
-
エラーの詳細の損失: エラーに広範な情報(ペイロード、HTTPステータスコード、エラーコードなど)が含まれている場合、このアプローチでは、
doSth
のエラーメッセージが新しく構築されたエラーに追加されるだけです。元のスタックトレースを含む、他の重要な詳細は失われます。 -
ログの可読性の低下: 潜在的なエラーポイントが2つ以上ある場合、ログが乱雑になり、解釈が難しくなる可能性があります。
-
意図を表現する際の曖昧さ: コードは、新しいエラーがキャッチされている特定の
doSth
関数によって引き起こされていることを明示的に伝えておらず、コードの可読性を向上させる余地があります。
error.cause
の紹介
これらの問題に対処するために、ECMAScript 2022ではerror.cause
が導入されました。
この機能により、開発者は新しいエラーオブジェクトを作成する際に、エラーの根本原因を指定できます。error.cause
を使用すると、エラーのチェーンを確立できるため、問題の根本原因をデバッグおよび追跡するのが容易になります。
簡単な例を次に示します。
try { // エラーをスローする可能性のある操作 } catch (error) { throw new Error('問題が発生しました', { cause: error }); }
このアプローチを使用すると、エラー間の因果関係を構築できます。例えば:
const func = () => { try { doSth('A'); } catch (error) { throw new Error('Aからのエラー', { cause: error }); } try { doSth('B'); } catch (error) { throw new Error('Bからのエラー', { cause: error }); } };
これにより、下位レベルの関数(例:doSth('A')
)によってスローされたエラーをキャッチし、関連するコンテキストを追加する新しいエラーをスローし(例:「doSth('A')
の実行中にエラーが発生しました」)、元のエラーの詳細(例:「Aは不正な引数です」)を保持できます。
エラーのチェーンを構築する
error.cause
のもう1つの利点は、リンクされたエラーのチェーンを作成できることです。これにより、開発者はアプリケーションの複数のレイヤーを介して問題を追跡できます。
const func = () => { try { try { try { doSth('A'); } catch (error) { throw new Error('深さ3のエラー', { cause: error }); } } catch (error) { throw new Error('深さ2のエラー', { cause: error }); } } catch (error) { throw new Error('深さ1のエラー', { cause: error }); } }; console.log(error.cause.cause); // 深さ3のエラー
Node.jsでは、cause
を含むエラーはコンソールで特別に処理されます。関連するすべてのエラースタックが出力されます。
const cause = new Error('リモートHTTPサーバーが500ステータスで応答しました'); const symptom = new Error('メッセージの送信に失敗しました', { cause }); console.log(symptom); // Prints: // Error: The message failed to send // at REPL2:1:17 // at Script.runInThisContext (node:vm:130:12) // ... 7 lines matching cause stack trace ... // at [_line] [as _line] (node:internal/readline/interface:886:18) { // [cause]: Error: The remote HTTP server responded with a 500 status // at REPL1:1:15 // at Script.runInThisContext (node:vm:130:12) // at REPLServer.defaultEval (node:repl:574:29) // at bound (node:domain:426:15) // at REPLServer.runBound [as eval] (node:domain:437:12) // at REPLServer.onLine (node:repl:902:10) // at REPLServer.emit (node:events:549:35) // at REPLServer.emit (node:domain:482:12) // at [_onLine] [as _onLine] (node:internal/readline/interface:425:12) // at [_line] [as _line] (node:internal/readline/interface:886:18)
結論
- エラーのコンテキストと詳細の両方にすぐにアクセスできる場合、デバッグは非常に簡単になります。
- これを実現するための効果的な方法の1つは、
error.cause
機能を使用して、「キャッチ+コンテキスト付きで再スロー」パターンを採用することです。
try { doSth(); } catch (error) { throw new Error('doSthに関連するコンテキスト', { cause: error }); }
このアプローチは、エラーの追跡可能性を向上させるだけでなく、コードの可読性と保守性も向上させます。
Leapcellは、Node.jsプロジェクトをクラウドにデプロイするための最良の選択肢です。
Leapcellは、Webホスティング、非同期タスク、およびRedis向けの次世代サーバーレスプラットフォームです。
多言語サポート
- Node.js、Python、Go、またはRustで開発します。
無制限のプロジェクトを無料でデプロイ
- 使用量に対してのみ支払い — リクエストも料金もかかりません。
比類のないコスト効率
- アイドル料金なしの従量課金制。
- 例:25ドルで平均応答時間60ミリ秒で694万リクエストをサポートします。
合理化された開発者エクスペリエンス
- 簡単なセットアップのための直感的なUI。
- 完全に自動化されたCI/CDパイプラインとGitOps統合。
- 実用的な洞察のためのリアルタイムメトリクスとロギング。
簡単なスケーラビリティと高性能
- 高い同時実行性を容易に処理するための自動スケーリング。
- 運用上のオーバーヘッドはゼロ — 構築に集中するだけです。
詳細については、ドキュメントをご覧ください。
Xでフォローしてください:@LeapcellHQ