try-catch — エラー処理の基本
このトピックを終えると
try-catchの動作原理を理解し、どこでエラーを捕捉すべきかを判断できるようになります。
エラーが発生するとプログラムが停止します
const data = JSON.parse("not json");
console.log("この行は実行されません");JSON.parseがエラーをスローすると、それ以下のコードはすべて実行されません。ブラウザでは、そのスクリプトの実行が停止します。
try-catchでエラーを捕捉します
try {
const data = JSON.parse("not json");
} catch (error) {
console.log("パースに失敗:", error.message);
}
console.log("この行は実行されます");tryブロック内でエラーが発生すると、すぐにcatchブロックに移動します。プログラムは停止しません。 catch以降のコードも正常に実行されます。
errorオブジェクトは、.message(エラーメッセージ)と.stack(コールスタック)というプロパティを持ちます。
throwでエラーを直接スローします
JavaScriptが自動的にスローするエラーに加えて、自分でエラーをスローすることもできます。
function divide(a, b) {
if (b === 0) {
throw new Error("0で割ることはできません");
}
return a / b;
}
try {
divide(10, 0);
} catch (error) {
console.log(error.message); // "0で割ることはできません"
}throwは、関数実行をすぐに中断し、最も近いcatchにエラーを伝播します。途中の関数はすべてスキップされます。
finally — 常に実行
try {
const file = openFile("data.txt");
processFile(file);
} catch (error) {
console.log("処理に失敗");
} finally {
closeFile(file);
}finallyは、エラーが発生しても発生しなくても常に実行されます。ファイルやネットワーク接続のクローズ、ローディング状態の初期化など、「クリーンアップ」処理に使用します。
setLoading(true);
try {
const data = await fetchData();
setData(data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}async/awaitとtry-catch
非同期関数でも、try-catchは同じように動作します。
async function loadUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (error) {
console.log("ユーザーのロードに失敗:", error.message);
return null;
}
}awaitの前にtryを記述すると、ネットワークエラーとHTTPエラーの両方を捕捉できます。
どこで捕捉すべきか
すべての場所にtry-catchを配置すると、コードが冗長になります。原則があります。
エラーを回復できる場所で捕捉します。 API呼び出しが失敗した場合に、エラーメッセージを表示したり、再試行したりできる場所で捕捉します。単にログを出力するだけの場合は、捕捉する必要はありません。
// 悪い例:捕捉するだけで何もしない
try {
doSomething();
} catch (e) {
// 無視
}
// 良い例:ユーザーにフィードバックを提供する
try {
await saveData(formData);
showSuccess("保存されました");
} catch (error) {
showError("保存に失敗: " + error.message);
}重要なポイント
try-catchは、エラーがプログラムを停止させないようにします。throwで意図的にエラーをスローし、最も近いcatchで捕捉します。 エラーを回復できる場所でのみcatchを使用してください。