async/await讓JavaScript異步編程變得更加直觀和優雅。然而,在處理錯誤時,這種語法糖也隱藏了許多容易被忽視的陷阱。作為一名經歷過無數深夜緊急修復的開發者,分享下生產環境中親身經歷的5個async/await錯誤處理陷阱,以及如何避免它們。
陷阱一:忘記使用try/catch捕獲錯誤
最常見也最基礎的錯誤是完全忘記處理異步操作中可能發生的異常。
async function fetchUserData(userId) {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.JSON(); // 如果響應不是有效JSON會拋出錯誤
return userData;
}
這段代碼在遇到網絡錯誤、服務器錯誤或無效JSON時會直接拋出未捕獲的異常,可能導致整個應用崩潰。
正確做法:
async function fetchUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const userData = await response.json();
return userData;
} catch (error) {
console.error(`獲取用戶數據失敗: ${error.message}`);
// 返回默認值或重新拋出錯誤
throw new Error(`獲取用戶ID ${userId} 的數據失敗: ${error.message}`);
}
}
陷阱二:在Promise鏈中丟失錯誤
當混合使用async/await和.then()/.catch()鏈式調用時,錯誤處理會變得混亂。
async function processData() {
const rawData = await fetchData();
// 錯誤:以下的錯誤不會被當前函數的try/catch捕獲
processResult(rawData).then(result => {
// 使用結果...
});
}
正確做法:
async function processData() {
try {
const rawData = await fetchData();
// 方法一:在鏈中添加錯誤處理
processResult(rawData)
.then(result => {
// 使用結果...
})
.catch(error => {
console.error("處理結果時出錯:", error);
});
// 方法二(更好):完全使用await
const result = await processResult(rawData);
// 使用結果...
} catch (error) {
console.error("處理數據失敗:", error);
}
}
陷阱三:在循環中的錯誤處理不當
在循環中使用async/await時,錯誤處理尤其複雜。
一個項目的錯誤會中斷整個處理流程,這可能不是你想要的行為。
正確做法:
或者使用Promise.allSettled處理並行操作:
陷阱四:不處理異步函數中的同步錯誤
一個常見誤解是認為try/catch只能捕獲await表達式的錯誤,而忽略了同步代碼也會拋出錯誤。
正確做法:
陷阱五:未考慮await表達式返回的Promise狀態
await表達式可能返回已解決的Promise,但其值可能表示錯誤狀態。
正確做法:
async function fetchResource() {
try {
const response = await fetch('/api/resource');
if (!response.ok) {
throw new Error(`API錯誤: ${response.status} ${response.statusText}`);
}
const data = await response.json();
return data;
} catch (error) {
console.error("獲取資源失敗:", error);
throw error;
}
}
歡迎補充。