async/awaitでajax(axios)処理のエラー時の処理を考える
async
,await
を使った非同期処理(特にajax
処理)の実装でエラー時の処理をどのように実装したらいいか、いろいろと調べてみました。
try-catchを使う方法
最初は以下のように、await
の処理をtry-catch
で囲う方法で実装しました。
let response;
try {
response = await ajax();
} catch (e) {
console.log('エラー発生');
return;
}
console.log(response);
この方法だと、try
の中に複数のawait
の処理があった場合、catch
に入った時にどのawait
処理でエラーになったのかというのがわからないです。(サーバー処理でエラー時のレスポンスデータに工夫が必要になる)
個々のawait
処理をtry-catch
で囲うのならPromise
で実装したほうがスッキリする気もするので、他の方法を考えました。
responseデータで正常終了したかどうか判定する
サーバー処理では各処理ごとに個別にtry-catch
で囲ったりせずに、グローバルレベルで1箇所にエラー処理を実装することが多かったのですが、JavaScript
の場合は考え方が少し違うように感じました。
ajax
処理ではサーバー処理でのバリデーションエラーやネットワーク環境によるエラーなど、想定するべきエラーがたくさんあるので、サーバー処理のように、「エラー時はエラー画面に飛ばす」などのようにエラー時の処理を共通化するのは難しいです。
バリデーションエラーなどの処理をcatch
処理で実装するのは違和感があったので、このような想定されたエラーの場合、ajax
処理自体は正常終了するようにして、response
のデータによってエラーかどうか判定する方法がいいと思いました。
ajaxライブラリの修正
ajax
ライブラリのレスポンス時の処理を修正します。
ajax
ライブラリにaxios
を使用してる場合は、interceptors.response
の処理を実装します。
正常時、エラー時ともに、Promise
は成功として扱い、オブジェクトを返すようにします。
正常時はdata
、エラー時はerror
をオブジェクトにセットしています。
axios.interceptors.response.use((response) => {
return Promise.resolve({
data: response.data
});
}, (error) => {
return Promise.resolve({
error: error.response
});
});
await処理でajaxの結果を受け取る
await
の処理で、上記でセットしたオブジェクトを受け取ります。
以下のように分割代入で受け取るとスッキリします。
const { data, error } = await ajax();
if (error) {
// エラー時の処理
} else {
// 正常時の処理
}
予期せぬエラーの場合(error.response.status = 500
など)はエラー内容をthrow
したりする必要があるかもしれませんが、await
処理ごとにエラー処理を実装できるようになりました。
もっと綺麗な方法が見つかるかもしれませんが、バリデーションエラーのような想定しておくべきエラーはcatch
に飛ばさずに処理を実装したかったので、最終的にはこのような形になりました。