ES6のPromiseにおける例外処理

Promiseの例外のハンドリングについてまとめる。

個人的にベストプラクティスだと思う方法

基本的には、以下の2点で考えると良いと思う。

  • 例外が発生する可能性がある箇所
  • 処理の流れを判断する箇所

例えば、以下の関数は例外を発生させ、それを明示的に例外を外へ伝播させる。

const promiseFnA = () => {
  return new Promise((resolve, reject) => {
    reject(new Error('this is a error.'));
  })
  .then(() => {
    console.log('not executed')
  })
  // 例外を処理せず、外へ伝播させる。
  .catch((error) => {
    throw error;
  });
};

上記の関数の呼び出しを行う個所では、例外を適切に処理する必要がある。 例えば以下の関数は、例外を処理する関数である。

const promiseFnB = () => {
  return promiseFnA()
  // 標準エラー出力することで例外を処理する
  .catch(console.error);
}

このように、設計として例外を発生させる個所と処理する個所をわけるようにする。

例外処理の設計のポイント

try catchでもPromiseでも本質的には変わらない。

末端では例外を処理しない

基本的には、末端では例外を処理しないようにする。

なぜなら、個別に処理の中止や回復の判断を行うと全体的な流れが見えなくなってしまうから。 そうなると、大変な数の例外を相手にしなければならなくなり、どこかで握りつぶしたりする可能性がある。 そのため、末端の処理では例外を発生させるだけに留めると良い。

例外を処理する個所を決める

末端の処理から発生した例外を捕捉して、後者の処理の流れを判断する箇所を決める。 階層で構造化されている場合は、できるだけ上位の呼び出しもと階層で例外を捕捉するようにした方が扱いやすい。

エラーコードなどを定義する

末端では、例外の種類によってErrorオブジェクトにエラーコードなどを設定するとよい。 そうすることで、上位の階層でどのような例外処理を行うべきかの判断ができるようになる。

まとめ

例外処理で困らないためには、以下の点を意識して設計すること。

  • 末端では、エラーコードを設定しつつ、例外を発せさせる。
  • 中枢では、エラーコードによって、判断を行い、適切な例外処理を行う。
  • 中間では、例外を握りつぶさない。

これらはPromise関係なく、例外処理に対して普遍的に適用できるルールだと思う。

設定するエラーコードについては、コメントに明示しておくとなお親切だと思う。