フロントエンドにおけるエラーハンドリング
例えばアプリを操作していて、
・どこをクリックしても反応しない
・ローディングが回ったまま
などが起きるとユーザーが戸惑ってしまい、UX的に良くない。
何かしらの処理が失敗した際に、ユーザー(UI側)にきちんと伝えることがフロントエンドにおけるエラーハンドリング
UI側にエラーを表示するメリット
・処理に失敗したことを伝えることで、再試行すればいいという事がわかる
・エラー発生時にエラーコードなどを出しておけば、問い合わせ時にどこで起きたエラーなのかを判別しやすく解決しやすくなる
エラーハンドリングの実装が必要なケース:
・APIとの通信処理(データが取れなかったり、リクエストが失敗した時)
・ライブラリの初期化
など
エラーハンドリングの実例:
-
APIがレスポンスオブジェクトに失敗か、成功かを返してくれる
isOK, isSuccessとかのフラグを返してくれる設計であればそれを使う一番シンプルな単一のエンドポイントを呼ぶとき
const result = await fetchData()
If (!result.isSuccess) {
// エラー表示処理を呼ぶ
}
- データ量が多くて、分割でリクエスト
Promise.allで複数のAPIを並列で呼んで、配列でレスポンスを受ける場合
const results = Promise.all([
fetchData1,
fetchData2,
fetchData3,
])
const flatResults = results.flat()
const errorResponse = flatResults.find((res) => !res.isSuccess)
If (errorResponse) {
// エラー表示処理を呼ぶ
}
results
にはレスポンスが配列で入るので、全て失敗か?一部失敗か?どちらでエラー判定するかは処理の性質による。
try catch文
try catch文は、予想外のエラーを意図的に回避するための処理です。
つまり、エラーが発生するかもしれない箇所をtryブロックに記述し、プログラムが異常終了しないような回避策をcatchブロックの中に記述します。
現在の現場では、エラーオブジェクトを返してくれないAPIとのやり取りでエラーハンドリングするためにtry catch文を使ってます。
try {
// 例外エラーが発生するかもしれない処理
} catch(e) {
// 例外エラーが起きた時に実行する処理
}
また、tryブロックの中で、try catchを書いて入れ子にする事も可能です。
if文などで分岐する事が多い
try {
if (条件1) {
try {
// 例外エラーが発生するかもしれない処理 1
} catch(e) {
// 例外エラーが起きた時に実行する処理
}
}
if (条件2) {
try {
// 例外エラーが発生するかもしれない処理 2
} catch(e) {
// 例外エラーが起きた時に実行する処理
}
}
} catch(e) {
//例外エラーが起きた時に実行する処理
}
throw
tryブロックでthrowすると意図的に例外を発生させて処理をそこで終了させる事ができる。後続処理に行かないので、後続処理へ進めたいときはthrowしないで、エラーログを出力だけする等がいい。
catchブロックでthrowすると、キャッチした例外そのものをスローすることができる。
例外をthrowして、処理を止めるか、そのまま進めるかはその処理の性質によるので、実装で判断する。
まとめ
-
エラー処理は意識して作らないといけない
-
エラー処理は書かなくても成功すれば動いてしまうので、サボってしまいがちだが、ユーザー体験を下げてしまうので、手間がかかってもやるべき
-
正常処理を書き、例外処理を考える