async/await のエラーハンドリング - JavaScript
async/await は Promise を同期的なコードのように書ける構文です。エラーハンドリングも try-catch が使えるため、直感的に書けます。
基本的な try-catch
await している処理でエラーが発生すると、通常の例外と同じように catch で捕捉できます。
async function fetchUser(id) {
try {
const response = await fetch(`/api/users/${id}`);
const user = await response.json();
return user;
} catch (error) {
console.error('ユーザー取得エラー:', error.message);
return null;
}
}Promise チェーンの .catch() と比べて、同期コードと同じ感覚で書けるのがメリットです。
finally も使える
try-catch-finally の構文もそのまま使えます。
async function loadData() {
showLoading();
try {
const data = await fetchData();
displayData(data);
} catch (error) {
showError(error);
} finally {
hideLoading(); // 必ず実行される
}
}エラーの再スロー
catch でログを取った後、上位の呼び出し元にもエラーを伝えたい場合は再スローします。
async function processOrder(orderId) {
try {
const order = await fetchOrder(orderId);
await validateOrder(order);
await submitOrder(order);
} catch (error) {
console.error('注文処理エラー:', error);
throw error; // 呼び出し元に伝える
}
}複数の await とエラー
複数の await がある場合、最初にエラーが発生した時点で catch に移ります。
async function main() {
try {
const a = await stepA(); // ここでエラーが起きると
const b = await stepB(); // ここは実行されない
const c = await stepC(); // ここも実行されない
return c;
} catch (error) {
console.error('いずれかのステップで失敗:', error);
}
}並列実行時のエラー処理
Promise.all を await する場合も、try-catch で捕捉できます。
async function fetchAllData() {
try {
const [users, posts] = await Promise.all([
fetch('/api/users').then(r => r.json()),
fetch('/api/posts').then(r => r.json())
]);
return { users, posts };
} catch (error) {
console.error('データ取得に失敗:', error);
return { users: [], posts: [] };
}
}Promise.all は1つでも失敗すると全体が失敗します。個別にエラーを処理したい場合は Promise.allSettled を使います。
try-catch を使わないパターン
毎回 try-catch を書くのが冗長に感じる場合、呼び出し側で catch する方法もあります。
// 関数側ではエラー処理しない
async function fetchUser(id) {
const response = await fetch(`/api/users/${id}`);
if (!response.ok) {
throw new Error(`HTTP ${response.status}`);
}
return response.json();
}
// 呼び出し側でハンドリング
fetchUser(1)
.then(user => console.log(user))
.catch(error => console.error('失敗:', error));ヘルパー関数を使う
Go 言語風に、エラーと結果をタプルで返すパターンもあります。
async function safeAsync(promise) {
try {
const result = await promise;
return [null, result];
} catch (error) {
return [error, null];
}
}
// 使い方
const [error, user] = await safeAsync(fetchUser(1));
if (error) {
console.error('エラー:', error);
} else {
console.log('ユーザー:', user);
}try-catch のネストを減らしつつ、エラー処理を明示的に行えます。
よくある間違い
async 関数の呼び出しで await を忘れると、エラーが捕捉されません。
async function main() {
try {
fetchData(); // await 忘れ!
console.log('完了'); // すぐに実行される
} catch (error) {
// fetchData のエラーは捕捉されない
console.error(error);
}
}await あり
Promise が解決するまで待ち、エラーも捕捉される
await なし
Promise が返るだけで待たない。エラーは未処理になる
async/await を使うときは、await の付け忘れに注意しましょう。