JS 非同期処理のデバッグ
1. 非同期処理のバグ
非同期(Asynchronous)のバグは、コードが「後で」実行されるため、特定が非常に困難です。
このセクションでは、fetch()、Promise、async/await をデバッグするための実用的な方法を紹介します。
非同期のデバッグ(Debugging)の本質は、「コードがどこで止まったか」を見つけ、次に「なぜ止まったか」を突き止めることにあります。
2. なぜ非同期のバグは「見えない」のか
非同期コードは、関数がすでにリターン(Return)した後に失敗することがよくあります。これが、何も起きていないように感じさせる原因です。
async function loadData() {
let response = await fetch("missing.json");
let data = await response.json();
console.log(data);
}
loadData();
console.log("完了");この場合、たとえ後から fetch が失敗したとしても、完了 というメッセージは先に出力されてしまいます。
3. ルール 1:必ずエラーをハンドリングする
未処理の Promise の拒否(Rejection)は、開発者を混乱させます。エラーは早い段階で、かつ明確に処理しましょう。
async function loadData() {
try {
let response = await fetch("missing.json");
let data = await response.json();
console.log(data);
} catch (error) {
// ネットワークエラーや JSON 解析エラーをここでキャッチします
console.log(error);
}
}これにより、通信エラーやデータ形式の不備を即座に把握できます。
4. ルール 2:response.ok を確認する
fetch は、404 などの HTTP エラーが発生しても Reject されません。
そのため、必ず response.ok をチェックする必要があります。
async function loadData() {
try {
let response = await fetch("missing.json");
if (!response.ok) {
console.log("HTTP エラー:", response.status);
return;
}
let data = await response.json();
console.log(data);
} catch (error) {
console.log("ネットワークエラーが発生しました");
}
}この実装により、HTTP エラーとネットワーク自体のエラーを切り分けてデバッグできます。
5. ルール 3:適切な内容をログに出力する
Promise オブジェクトをログに出力することと、実際のデータをログに出力することは別物です。
まずは レスポンス(Response)とステータスを確認しましょう。
async function loadData() {
let response = await fetch("data.json");
console.log(response.status);
console.log(response.headers.get("content-type"));
}これにより、サーバーが期待通りの形式でデータを返しているかを確認できます。
6. Network タブを活用する
ブラウザの Network(ネットワーク)タブ は、すべてのリクエストを表示します。これは fetch の問題をデバッグする最も速い方法です。
- リクエスト URL が正しいか確認する
- ステータスコード を確認する
- レスポンスボディ(Response body)を確認する
- レスポンスの Content-Type を確認する
フェッチに関するバグの多くは、実は JavaScript のバグではありません。URL の指定ミスやサーバーのレスポンス不備が原因であることがほとんどです。
7. await 行にブレークポイントを設置する
await が記述されている行には、ブレークポイント(Breakpoint)を設定できます。
これにより、非同期ステップの前後で値(Value)を検証できます。
async function loadData() {
let response = await fetch("data.json");
let data = await response.json();
console.log(data);
}最初の await 行にブレークポイントを設定し、ステップオーバー(Step over)しながら response の中身をインスペクト(検査)してください。
8. よくある非同期処理のエラー
await の付け忘れは、初心者が最も陥りやすいミスです。
間違った例
async function loadData() {
let response = await fetch("data.json");
let data = response.json(); // await が欠落しています
console.log(data); // JSON ではなく Promise がログ出力されます
}正しい例
async function loadData() {
let response = await fetch("data.json");
let data = await response.json();
console.log(data);
}9. Promise チェーンのデバッグ
Promise はチェーンのどこで失敗するか分かりません。
各ステップの間にログを挟むことで、どこで問題が発生しているかを特定できます。
fetch("data.json")
.then(function(response) {
console.log("レスポンスを受信しました");
return response.json();
})
.then(function(data) {
console.log("データの解析が完了しました");
console.log(data);
})
.catch(function(error) {
console.log("失敗しました");
console.log(error);
});ネストされたコールバックよりも、このようにチェーンの最後に一つ catch() を置く方が、エラー管理は遥かに容易になります。