エラー処理

プログラミングでは、エラー処理は多くの落とし穴を持つ複雑なトピックです。 フレームワークの制約の中でコードを書くことはさらに困難になります 間違いを扱うにはフレームワークが間違いを発生させる方法と

この記事では、エラーがJavaScriptフレームワークとOwlによってどのように処理されるかについての幅広いストロークを描きます。 共通の問題を回避する方法を提案しています

JavaScript でのエラー

Odoo でエラーがどのように処理されるか、エラー処理の動作をカスタマイズする方法と場所について説明します。 同じページにいることを確認するのは良いアイデアだ 正確には"エラー"だ JavaScriptにおけるエラー処理の特殊性の一部と同様に。

`Error`クラス

エラー処理について話すときに最初に思い浮かぶのは、組み込みの Error クラス、またはそれを拡張するクラスです。 この記事の残りの部分では、このクラスのインスタンスであるオブジェクトを参照するとき。 Error object という用語はイタリック体で使用します。

何でも投げられます

JavaScript では、任意の値をスローできます。 Error オブジェクト を投げるのが慣例ですが、他のオブジェクトやプリミティブを投げることもできます。 *Error オブジェクト*ではないものを投げることはお勧めしません。 Odoo JavaScriptフレームワークは、これらのシナリオに対応できる必要があります。 私たちがしなければならない設計上の決断を理解するのに役立ちます

*Error object*をインスタンス化すると、ブラウザは「コールスタック」の現在の状態に関する情報を収集します(適切なコールスタックのいずれか)。 または非同期関数とPromise継続のための再構築コールスタック)。 この情報は「スタックトレース」と呼ばれ、デバッグに非常に役立ちます。Odooフレームワークは利用可能な場合、このスタックトレースをエラーダイアログに表示します。

*Error object*ではない値を投げると、ブラウザーは現在のコールスタックに関する情報を引き続き収集します。 しかし、この情報は JavaScript では利用できません。エラーが処理されていない場合は、devtools コンソールでのみ利用できます。

*Error objects*をスローすることで、ユーザがバグレポートを必要に応じてコピー/ペーストできる詳細情報を表示することができます。 エラー処理はより堅牢になりますクラスに基づいてエラーをフィルタリングすることができます 残念ながら、JavaScript は catch 節の中で error クラスによるフィルタリングを構文的にサポートしていませんが、比較的簡単に実行できます。

try {
  doStuff();
} catch (e) {
  if (!(e instanceof MyErrorClass)) {
    throw e; // caught an error we can't handle, rethrow
  }
  // handle MyErrorClass
}

Promise拒否はエラーです

Promiseの採用の初期の頃、Promiseはしばしば結果と「エラー」の結合を格納する方法として扱われました。 そして、約束の拒絶反応をソフトな失敗を知らせる方法として使うのはかなり一般的でした。 一見良いアイデアのように思えるかもしれませんが、 ブラウザとJavaScriptのランタイムは長い間、拒否されたPromiseをエラーが投げられたのと同じ方法で扱い始めています:

  • 非同期関数を投げると、スローされた値で拒否される Promise を拒否理由として返すのと同じ効果があります。

  • async 関数内の catch ブロック catch は対応する try ブロックで待ち受けた Promise を拒否しました。

  • ランタイムは拒否された約束のスタック情報を収集します

  • 却下された Promise が同期的にキャッチされていない場合、global/window オブジェクトのイベントがディスパッチされます。 イベントで preventDefault が呼び出されない場合、ブラウザーはエラーを記録し、ノードのようなスタンドアロンランタイムはプロセスを停止します。

  • Promiseが拒否されたときにデバッガ機能「exceptionsで一時停止」は一時停止します

これらの理由から、Odoo フレームワークは Promise をスローされたエラーとまったく同じ方法で取り扱います。 エラーをスローしない場所では、拒否された Promise を作成しないでください。また、常に Error オブジェクト の Promise を拒否理由として拒否します。

error イベントはエラーではありません

With the exception of error events on the window, error events on other objects such as <media>, <audio> <img>, <script> and <link> elements, or XMLHttpRequest objects are not errors. For the purpose of this article, "error" specifically refers only to thrown values and rejected promises. If you need to handle errors on these elements or want them to be treated as errors, you need to explicitly add an event listener for said event:

const scriptEl = document.createElement("script");
scriptEl.src = "https://example.com/third_party_script.js";
return new Promise((resolve, reject) => {
  scriptEl.addEventListener("error", reject);
  scriptEl.addEventListener("load", resolve);
  document.head.append(scriptEl);
});

Odoo JS フレームワーク内のエラーのライフサイクル

Thrown errors はコールスタックを巻き戻して、それらを処理できる catch 節を見つけます。 エラーの処理方法は、コールスタックの巻き戻し中に発生するコードによって異なります。 事実上無限の場所エラーがスローされる可能性があります。 JSフレームワークのエラー処理コードには、いくつかの可能なパスしかありません。

モジュールのトップレベルにエラーが発生しました

JSモジュールがロードされると、そのモジュールの最上位レベルのコードが実行され、スローされる可能性があります。 フレームワークがこれらのエラーをダイアログで報告する場合があります。 モジュールの読み込みはJavaScriptフレームワークにとって非常に重要な瞬間です。いくつかのモジュールでエラーが発生すると、フレームワークのコードが完全に起動しなくなる可能性があります。 この段階でのエラー報告は"最善の努力"です。 ただし、モジュールの読み込み中にスローされるエラーは、常にブラウザコンソールにエラーメッセージを記録する必要があります。 なぜなら、このタイプのエラーは重要だからです。 アプリケーションが回復する方法はありませんし、定義中にモジュールがスローされることができないような方法でコードを書くべきです。 この段階で発生するエラーの処理と報告は、純粋にあなたを支援する目的で行われます。 開発者はエラーを発生させたコードを修正し エラーの処理方法をカスタマイズするメカニズムは提供していません

エラーサービス

エラーがスローされたがキャッチされなかった場合、ランタイムはグローバルオブジェクト (window ) に対してイベントをディスパッチします。 イベントのタイプは、エラーが同期的にスローされたか非同期的にスローされたかによって異なります。同期的にエラーが発生すると、error イベントが発生します。 そして、非同期コンテキスト内からスローされるエラーと、拒否された Promise は unhandledrejection イベントを送信します。

JSフレームワークには、エラー・サービスという、これらのイベントの処理専用のサービスが含まれています。 これらのイベントのいずれかを受信したとき エラーサービスは、スローされたエラーをラップするために使用される新しい Error object を作成することから始まります。 これは、任意の値を投げることができるためで、Promiseは`undefined`や`null`を含む任意の値で拒否することができます。 情報が含まれていることやその価値に関する情報を保存できることは保証されていません Error object は、スローされた値に関する情報を収集するために使用されます。これにより、あらゆるタイプのエラーに関する情報をフレームワークコードで均一に使用することができます。

エラーサービスには、このラッパー*エラーオブジェクト*にスローされたエラーの完全なスタックトレースが格納されており、デバッグモードが`assets`の場合。 ソースマップを使用して、各スタックフレームの機能を含むソースファイルに関する情報をこのスタックトレースに追加します。 バンドルされたアセット内の関数の位置は保持されます。便利な場合があるため、いくつかのシナリオがあります。 エラーに cause がある場合、このプロセスは cause チェーンを解除して完全なコンポジットスタックトレースを構築します。 Error objectscause フィールドは標準ですが、一部の主要なブラウザではエラーチェーンのスタックトレースが表示されません。 このため、この情報を手動で追加します。これはエラーが Owl フック内に投げられた場合に特に便利です。

ラッパーエラーに必要な情報がすべて含まれると、実際にエラーを処理するプロセスが開始されます。 これを行うために、error サービスは error_handlers レジストリに登録されているすべての関数を連続的に呼び出します。 どちらかの関数が真の値を返すまで、エラーが処理されたことを示します。 この後、エラーイベントで preventDefault が呼び出されなかった場合。 エラーサービスがラッパーのエラーオブジェクトに スタックトレースを追加できた場合 error service calls preventDefault on the error event and logs the stack trace in the console. これは、前述したように、いくつかのブラウザがエラーチェーンを正しく表示していないためです。 イベントのデフォルトの動作はブラウザがエラーを記録することです この動作をオーバーライドして、より完全なスタックトレースを記録します エラーサービスがスローされたエラーに関するスタックトレース情報を収集できなかった場合、preventDefault は呼び出しません。 これは、エラー以外の値(文字列、未定義またはその他のランダムなオブジェクト)を投げるときに発生する可能性があります。 このような場合、ブラウザはスタックトレース自体を記録します。これは、その情報を持っていますが、JS コードに公開することはありません。

error_handlers レジストリ

`error_handlers`レジストリは、JSフレームワークが"generic"エラーを処理する方法を拡張する主な方法です。 一般的なエラーは、この文脈では、多くの場所で発生するエラーを意味しますが、それは均一に処理されるべきです。いくつかの例:

  • UserError: ユーザーが、ビジネス上の理由からPythonコードが無効と判断した操作を実行しようとしたとき。 PythonコードはUserErrorを発生させ、rpc関数はJavaScriptで対応するエラーをスローします。 これはどこでもrpc上で起こる可能性があります このようなエラーを開発者が明示的に処理する必要はありません 私たちはどこでも同じ動作を行いたいと考えています。現在実行中のコード(これはスローで達成されます)を停止してください。 ユーザーに何がうまくいかなかったかを説明するダイアログを表示します。

  • AccessError: ユーザーエラーと同じ推論:それはいつでも起こることができ、それが起こる場所に関係なく同じ方法で表示される必要があります

  • LostConnection: 同じ推論を再び。

エラーをエラーとしてエラーにする

Owl コンポーネントの登録または変更は、Web クライアントの機能を拡張する主な方法です。 そのように、投げられるほとんどのエラーは、何らかの方法でOwlコンポーネントから投げられます。いくつかのシナリオがあります:

  • コンポーネントのセットアップまたはレンダリング中に投げます

  • ライフサイクルフック内から投げ

  • イベントハンドラからの投げ

イベントハンドラやイベントハンドラから直接または間接的に呼び出される関数やメソッドからエラーを投げることは、OwlのコードもJSフレームワークのコードもコールスタックに含まれていないことを意味します。 エラーをキャッチしない場合は、エラーサービスに直接着陸します。

コンポーネントのセットアップまたはレンダリング中にエラーを投げたとき、Owl はエラーをキャッチし、コンポーネント階層を上げます。 `onError`フックを持つ登録されたエラーハンドラを持つコンポーネントに、エラーの処理を試みるようにします。 エラーがそれらのいずれかによって処理されていない場合、Owl は破損した状態にある可能性があるため、アプリケーションを破棄します。

関連項目

Owl documentation の処理エラー

Odooの中には、エラーが発生した場合にアプリケーション全体をクラッシュさせたくない場所があります。 フレームワークには`onError`フックを使う場所がいくつかあります。 アクションサービスは、エラーを処理するコンポーネントにアクションとビューをラップします。 クライアントアクションまたはビューがレンダリング中にエラーをスローした場合、前のアクションに戻ろうとします。 エラーは、エラーダイアログを関連づけて表示できるように、エラーサービスに送信されます。 フレームワークが「user」コードを呼び出すほとんどの場所でも同様の戦略が使用されています。一般的に、欠陥のあるコンポーネントのエラーダイアログを表示するのをやめます。

フックのコールバック関数の中にエラーが発生した場合。 フックが登録された場所に関するスタック情報を含む新しい Error オブジェクト を作成し、その原因をスローされた値として設定します。 これは、元のエラーのスタックトレースには、このフックを登録したコンポーネントの情報が含まれていないためです。 フックについての情報しか含まれていません フックは Owl コードによって呼び出されるため、ほとんどの情報は 一般的に 開発者にとってはあまり役に立ちません。 どこでフックが登録されているのか、どのコンポーネントが非常に便利なのかを知ることができます。

「OwlError: The following error occurred in <hookName>」というエラーを読み込むときは、コンポジットスタックトレースの両方の部分を読み込んでください:

Error: The following error occurred in onMounted: "My error"
  at wrapError
  at onMounted
  at MyComponent.setup
  at new ComponentNode
  at Root.template
  at MountFiber._render
  at MountFiber.render
  at ComponentNode.initiateRender

Caused by: Error: My error
  at ParentComponent.someMethod
  at MountFiber.complete
  at Scheduler.processFiber
  at Scheduler.processTasks

最初のハイライトされた行は、どのコンポーネントが onMounted フックを登録したかを示し、2番目のハイライトされた行は、どの関数がエラーを投げたかを示します。 この場合、子コンポーネントは親からの props として受け取った関数を呼び出します。 その関数は親要素の方法です どちらの情報も役に立ちます メソッドが間違って呼び出される可能性があるので (あるいはライフサイクルのある時点で)、子どもは間違って呼び出される可能性があります。 親のメソッドにはバグが含まれていることもあります

処理済みとしてエラーをマーク中

前の節では、2つのエラーハンドラを登録する方法について説明しました。一つは、 error_handlers レジストリに追加する方法です。 もう一つはフクロウで`onError`フックを使っています。 どちらの場合も、ハンドラはエラーを処理済みとしてマークするかどうかを決定する必要があります。

onError

onError`で登録されているハンドラの場合、再度投げない限り、エラーはOwlが扱うものとして扱います。 `onError で何をしようと、ユーザーインターフェイスはアプリケーションの状態と同期していない可能性があります。 エラーによりフクロウは作業を完了できませんでした エラーを処理できない場合は、それを再度投げて、残りのコードにそれを処理させる必要があります。

エラーを再度スローしない場合は、アプリケーションがエラーなしで再びレンダリングできるように、いくつかの状態を変更する必要があります。 この時点で、エラーを再スローしない場合は報告されません。 場合によっては、これは望ましいが、ほとんどの場合。 代わりに、フクロウ以外の別々のコールスタックでこのエラーをディスパッチする必要があります。 これを行う最も簡単な方法は、拒否理由としてエラーを伴う拒否された Promise を作成することです:

import { Component, onError } from "@odoo/owl";
class MyComponent extends Component {
  setup() {
    onError((error) => {
      // implementation of this method is left as an exercise for the reader
      this.removeErroringSubcomponent();
      Promise.reject(error); // create a rejected Promise without passing it anywhere
    });
  }
}

これにより、ブラウザーはウィンドウに unhandledrejection イベントをディスパッチします。 これはJavaScriptフレームワークのエラー処理を引き起こし、エラーを処理します。 ほとんどの場合、エラーに関する情報を含むダイアログを開くことができます。 これは、アクションサービスおよびダイアログサービスによって内部的に使用される戦略であり、エラーを報告しながら、壊れたアクションまたはダイアログのレンダリングを停止します。

`error_handlers`レジストリ内のHandler

`error_handlers`レジストリに追加されたハンドラは、異なる意味を持つ二つの方法でエラーを扱うようにマークできます。

最初の方法は、ハンドラが真の値を返すことです。 これは、ハンドラがエラーを処理し、処理可能なエラーの種類に一致するために、エラーが発生したことを意味します。 これは通常、エラーについてユーザに警告するためのダイアログまたは通知を開いたことを意味します。 これにより、エラーサービスが以下のハンドラをより高いシーケンス番号で呼び出すことを防ぎます。

もう一つの方法は、エラーイベントで preventDefault を呼び出すことです。これは異なる意味を持っています。 エラーを処理できると判断した後、 ハンドラーは、受け取ったエラーが通常の操作中に発生するかどうかを判断する必要があります。 preventDefault を呼び出すべきです。 これは一般的に、アクセスエラーや検証エラーなどのビジネスエラーに適用されます: ユーザーは、アクセスがないリソースへのリンクを他のユーザーと共有できます。 ユーザーは無効な状態のレコードを保存しようとすることができます。

preventDefault を呼び出さない場合、エラーは予期しないものとして扱われます。 テスト中にそのようなことが起きるとテストは失敗します一般的にコードの欠陥を示しています

できるだけエラーを投げないでください

エラーは、多くの方法で複雑さを導入します, ここにあなたがそれらを投げることを避けるべきいくつかの理由があります.

エラーは高価です

エラーはcallstackを巻き戻して情報を収集する必要があるため、エラーの発生は遅くなります。 さらに、JavaScript ランタイムは一般的に例外が稀であるという仮定で最適化されています。 通常はスローされないという仮定でコードをコンパイルします もっと遅いコードパスに戻りましょう

エラーをスローするとデバッグが難しくなります

例えば、ChromeやFirefoxの開発ツールに含まれているもののようなJavaScriptデバッガー。 例外がスローされたときに実行を一時停止できる機能があります。 また、キャッチされた例外でのみ一時停止するか、キャッチされた例外とキャッチされていない例外の両方で一時停止するかを選択できます。

Owl または JavaScript フレームワークによって呼び出されるコードの中でエラーが発生した場合 (e. を選択します。 、リソースを管理するため、エラーをキャッチし、エラーが重要かどうかを検査し、アプリケーションがクラッシュするかどうかを判断する必要があります。 エラーが期待され特定の方法で処理されるべきか

このため、JavaScript コード内で発生するほとんどのエラーは、ある時点でキャッチされます。 処理できなければ再投入されるかもしれませんが これは、Odoo 内で作業しているときに、"一時停止しない例外" 機能を使用することは効果的に役に立たないことを意味します。 JavaScriptフレームワークのコード内で常に一時停止しているため、元々エラーが発生したコードの近くではなく。

しかし、「キャッチされた例外で一時停止」機能は、すべての throw 文と拒否された約束に対して実行を一時停止するため、まだ非常に便利です。 これにより、開発者は例外的な状況が発生するたびに実行コンテキストを停止および検査することができます。

しかし、例外がほとんど投げられないと仮定すると、これは真実です。 例外が定期的にスローされた場合、ページ内のすべてのアクションによりデバッガが実行を停止する可能性があります。 そして開発者は、彼らが興味を持っている実際の例外的なシナリオに到達する前に、多くの「ルーチン」の例外を踏む必要があるかもしれません。 いくつかの状況では、デバッガの再生ボタンをクリックするとページからフォーカスが削除されるためです。 キーボードのショートカットを使わなくても興味深いスローシナリオにアクセスできなくなるかもしれません 実行を再開するには 開発者の経験が悪くなります

スローすると、コードの通常のフローが壊れます

エラーを投げると、常に実行すべきようなコードがスキップされる可能性があります。これにより、多くの微妙なバグやメモリーリークが発生する可能性があります。 簡単な例は次のとおりです。

eventTarget.addEventListener("event", handler);
someFunction();
eventTarget.removeEventListener("event", handler);

このコードブロックでは、イベントリスナーをイベントターゲットに追加し、そのターゲットにイベントをディスパッチする関数を呼び出します。 関数呼び出し後、イベントリスナーを削除します。

someFunction がスローされた場合、イベントリスナーは決して削除されません。 つまり、このイベントリスナーに関連付けられたメモリは効果的に漏洩し、eventTarget 自体が解放されない限り、解放されることはありません。

メモリが漏洩した上に ハンドラがまだ取り付けられていることは、 someFunction の呼び出し以外の理由でディスパッチされるイベントが呼び出されることを意味します。 これはバグです。

これを考慮するには、呼び出しを try ブロックで囲み、finally ブロックでクリーンアップを囲む必要があります。

eventTarget.addEventListener("event", handler);
try {
  someFunction();
} finally {
  eventTarget.removeEventListener("event", handler);
}

これにより、上記の問題を回避できますが、これにはより多くのコードが必要になるだけでなく、関数がスローされる可能性のある知識も必要になります。 `try/finally`ブロックに入れるコードを全部ラップするのは難しいでしょう。

キャッチエラー

場合によっては、エラーをスローすることが知られているコードを呼び出す必要があり、これらのエラーのいくつかを処理したい場合があります。 心に留めておくべき二つの重要なことがあります:

  • エラーの型ではないエラーを再スローします。これは一般的に instanceof を使用して行う必要があります。

  • try ブロックをできるだけ小さくしてください。これは、あなたがキャッチしようとしているものではないエラーを避けます。 一般的に、try ブロックには one ステートメントを含める必要があります。

let someVal;
try {
  someVal = someFunction();
  // do not start working with someVal here.
} catch (e) {
  if (!(e instanceof MyError)) {
    throw e;
  }
  someVal = null;
}
// start working with someVal here

これはtry/catchで簡単ですが。 Promise を扱う場合は、catch 節にあるコードの大部分を誤ってラップする方がはるかに簡単です。 chatch:

someFunction().then((someVal) => {
  // work with someVal
}).catch((e) => {
  if (!(e instanceof MyError)) {
    throw e;
  }
  return null;
});

この例では、catch ブロックは実際に、その then ブロック全体のエラーをキャッチします。これは、私たちが望んでいるものではありません。 この例では、エラータイプに基づいて適切にフィルタリングするため、エラーを飲み込むことはありません。 しかし、これがもっと簡単かもしれないということがわかります。 もし、我々が単一のエラータイプを期待して、 instanceofチェックをしないと決めた場合。 ただし、前の例と異なり、null は someVal を使用するコードパスを通過しないことに注意してください。 これを避けるために、catch 節は通常、スローされる可能性のある Promise にできるだけ近くなければなりません。 を選択し、常にエラータイプをフィルタリングします。

制御フローの空きエラー

上記の理由から、ルーチンなこと、特に制御フローに対してエラーを投げることを避けるべきです。 関数が定期的に作業を完了できないと期待される場合は、例外を投げることなくその失敗を伝える必要があります。 サンプルコードを考えてみましょう:

let someVal;
try {
  someVal = someFunction();
} catch (e) {
  if (!(e instanceof MyError)) {
    throw e;
  }
  someVal = null;
}

このコードには問題となるものがたくさんあります。 最初に、変数`someVal`を`try/catch`ブロックの後にアクセスできるようにしたいからです。 そのブロックの前に宣言する必要があります。初期化後に割り当てる必要があるので、`const`にすることはできません。 この変数がコード内で後で再割り当てられる可能性に注意しなければならないので、これは道をさらに下る可読性を傷つけます。

第二に、私たちがエラーをキャッチするとき。 我々は誤差が実際に期待されていた誤差の種類であることを確認しなければなりません そうでなければ再度エラーをスローします これを行わなければ、正しく報告する代わりに、予期しないエラーを*実際に*飲み込むことになるかもしれません。e. をクリックします。 null または undefined のプロパティにアクセスしようとすると、TypeError をキャッチして飲み込むことができます。

最後に、 `try/catch`を追加するのを忘れた場合、 あなたはトレースバックに終わる可能性があります `try/catch`ブロックを追加しても、予期しないエラーを繰り返すのを忘れた場合、関連しないエラーを飲み込んでしまいます。 変数を再割り当てる必要がないようにしたい場合は、`try`ブロックの中に変数を使うブロック全体を移動させます。 `try`ブロックの中にコードが多いほど、関連のないエラーをキャッチできます。 エラータイプでフィルタするのを忘れた場合に飲み込むことができます また、インデントレベルをブロック全体に追加します。`try/catch`を入れ子にすることもできます。 最後に、実際にエラーをスローすると期待されている行を識別することが困難になります。

次のセクションでは、エラーの代わりに使用できるいくつかの代替手法を概説します。

null または undefined を返します

関数がプリミティブまたはオブジェクトを返した場合。 `null`または`undefined`を使用して、意図した仕事ができないことを示すことができます。 これはほとんどの場合で十分です。コードは次のようになります。

const someVal = someFunction();
// further
if (someVal !== null) { /* do something */ }

ご覧のとおり、これははるかに単純です。

オブジェクトまたは配列を返す

場合によっては、`null`または`undefined`の値は期待される戻り値の一部です。 この場合、返り値またはエラーを含むラッパーオブジェクトまたは2要素配列を返すことができます。

const { val: someVal, err } = someFunction();
if (err) {
  return;
}
// do something with someVal as it is known to be valid

または配列を使用します。

const [err, someVal] = someFunction();
if (err) {
  return;
}
// do something with someVal as it is known to be valid

注釈

2 要素配列を使用する場合は、エラーを最初の要素にすることをお勧めします。 破壊する時に間違って無視するのが難しいのです エラーをスキップするには、プレースホルダまたはカンマを明示的に追加する必要があります。一方、error が 2 番目の要素である場合。 最初の要素だけを単純に分解するのは簡単で誤ってエラーを処理するのを忘れてしまうのです

エラーをスローする時

前のセクションでは、エラーを避けるために多くの良い理由を与えます。 エラーを投げることが最善の方法である事例は何でしょうか?

  • 一般的なエラーは、多くの場所で発生する可能性がありますが、どこでも同じように扱われる必要があります。 アクセスエラーは、基本的にはどのRPCでも発生する可能性があり、ユーザーがアクセスしていない理由についての情報を常に表示したいと考えています。

  • ある操作に対して常に満たされるべきである前提条件が満たされない。例えば、ドメインが無効であるため、ビューをレンダリングできなかった。 これらのタイプのエラーは、通常、どこにでもキャッチされることを意図しておらず、コードが間違っているか、データが破損していることを示すものです。 投げるフレームワークが保釈され、壊れた状態での動作を防ぐことを強制します。

  • 深いデータ構造を再帰的に横断する場合 エラーを投げることは人間工学的であり、エラーの起こりやすさは、手動でエラーをテストし、多くのレベルの呼び出しを介してそれらを転送するよりも低くなります。 これは実際には非常にまれであるべきであり、この記事で述べられているすべての欠点に対して重視される必要がある。