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