JavaScriptにおけるエラーハンドリングの方法を解説
今回は、JavaScriptにおけるエラーハンドリングの方法を解説していきます。
プログラミングは、普通にコードを書くだけではなく、エラーハンドリングも適切にする必要があります。
けれど、その方法をきちんと解説している記事は少ないです。
なので、この記事を参考にしてエラーハンドリングの方法を学んでいきましょう。
そもそもエラーハンドリングとは?
エラーハンドリングとは、コンピュータプログラムが実行時にエラーを起こした際に、すぐに実行を終了せずにあらかじめ用意しておいた処理を行うことを言います。
また、例外処理と呼ぶ人もいます。
エラーハンドリングが組み込まれていないプログラムは、想定範囲外の入力データが与えられたなどの実行時エラーが起きると、エラーメッセージを表示するなどして即座に異常終了してしまいます。
けれど、エラーハンドリングをすることで、エラー発生時に事前に用意していた処理を実行させることができ、異常終了を防ぐことができます。
ちなみに、事前に用意しておく処理とは次のようなものです。
- ログを出す
- 返り値としてエラーオブジェクトを返す
- デフォルト値を返す
- 処理をスキップさせる
これらを用途に応じて適宜使い分けることになります。
エラーと例外について
ついでにエラーと例外について解説します。
同じ意味で使う人もいますが、使い分ける場合も多いです。
使い分ける場合は、次のような意味だと認識しておけばOKです。
- 例外:「想定できた」おかしな状態
- エラー:「想定外の」おかしな状態
つまり、例外処理とは想定できるおかしな状態に対して、あらかじめ対策を取っておくこととなります。
具体的なエラーハンドリングの方法
では次に具体的なエラーハンドリの方法を解説していきます。
まず、次のことを決めておきましょう。
- どこまで異常を検知すべきか
例えば、発生し得る全てのエラーに対してエラーハンドリングはかなり大変ですし、そもそもそこまで恩恵がないです。
なのでまずは、どこまでの例外を対策するのかを決めておきましょう。
次に、同期処理と非同期処理のエラーハンドリングのコードの書き方を解説していきます。
同期処理
同期処理はtry-catchでエラーハンドリングを行います。
tryで囲ったブロックの中でエラーが発生した場合は、その後続の処理は実行されず、catchのブロックの処理が実行されます。
また、finallyというものもあり、こちらはエラーが発生せずにtryのブロック内の処理が実行された場合も、エラーが起こってcatchブロックの処理が実行されても、最後に必ず処理が実行されます。
実際にコードは次の通りです。
try{
// 例外が発生し得る処理
bomb()
}catch(e){
// エラー時に実行される処理
console.log(e)
}finally{
// 最後に必ず実行される処理
console.log('finish')
}
tryのネスト
ちなみに、tryブロックはネストさせることが可能です。
ネストされたtryブロックでエラーが発生した場合は、同じ階層のcatchの処理が実行されます。
さらに親のcatchブロックの処理も実行したい場合は、エラーをthrowすればOKです。
エラーオブジェクト
先ほど「エラーをthrow」という表現をしましたが、こちらをもう少し詳しく解説していきます。
まず、JavaScriptにはthrowという機能があります。
これはエラーの発生を伝えるものになります。
もし、エラーがthrowされた場合、catchブロックが実行されますが、catchブロックが用意されていなかった場合は異常終了されてしまいます。
このthrow文は、エラーオブジェクトをthrowするのが一般的です。
そしてthrowされた内容がcatchブロックの引数として渡されます。
コードにすると次の通りです。
try{
throw new Error('エラーです')
}catch(e){
// Error: エラーです
console.log(e)
}
また、構文エラーなどが発生した場合もこのエラーオブジェクトが内部でthrowされているため、catchの処理が実行されるわけです。
ちなみに、このエラーオブジェクトにはname
やmessage
などの共通のプロパティがあります。
知っておいて損はないので、以下の参照を参考にどうぞ。
非同期処理
次に、非同期処理のエラーハンドリング方法を解説していきます。
非同期処理では、基本的にtry-catchをしてもエラーハンドリングができません。
なので例えば、Promisemを使った非同期処理場合は次のように例外処理をします。
fetch('/hoge/foo').then((result) => {
console.log(result)
}).catch((e) => {
console.log(e)
}).finally(() => {
console.log('finish')
})
このように非同期処理に対しては、thenとcatchを繋ぎます。
こうすることで、問題がない場合はthen以降の処理が実行され、エラーが発生した場合はcatchの処理が実行されます。
そして、最終的に必ずfinnalyが実行されます。
なので構造的にはtry-catchとほぼ同じです。
thenのネスト
ちなみに、次のようにthenが複数連なった時でも、途中何処かのthenの中でエラーが発生した場合は、catchの処理が実行されます。
fetch('https://qiita.com/api/v2/items')
.then((result) => {
console.log("hello")
}).then(() => {
throw new Error('エラーです')
}).catch((e) => {
console.log(e)
}).finally(() => {
console.log('finish')
})
また、以下のコードのようにthenがネストされた状態は、同じ階層でcatchがない場合はエラーがcatchされることはないです。
fetch('https://qiita.com/api/v2/items')
.then((result) => {
fetch('/hoge').then((r) => {
console.log("hello")
})
}).catch((e) => {
console.log(e)
}).finally(() => {
console.log('finish')
})
async/await
ちなみに、async/awaitを使った場合は普通にtry-catchを使うことができます。
コードにすると次の通りです。
try{
// 例外が発生し得る処理
await fetch('/hoge/foo')
}catch(e){
// エラー時に実行される処理
console.log(e)
}
以上が非同期処理のエラーハンドリング方法になります。
まとめ
今回は、JavaScriptにおけるエラーハンドリングの方法を解説しました。
ぜひ、こちらを参考にエラーハンドリングの理解を深めましょう。
宣伝
0からエンジニアになるためのノウハウをブログで発信しています。
また、YouTubeでの動画解説も始めました。
YouTubeのvideoIDが不正ですインスタの発信も細々とやっています。
興味がある方は、ぜひリンクをクリックして確認してみてください!
Discussion