JavaScript 工程師的修行之路(2):async await VS Promise
在 JavaScript 的世界裡,處理異步操作的方法有多種,其中最常被討論的就是 async/await 與 Promise.then()。這兩者各有特色與適用場景,理解它們的差異,有助於我們在開發中做出更明智的選擇。
接下來我將會從語法風格、錯誤處理、執行順序這三個面向說明一下兩者的差異。
語法風格與可讀性
async/await 的出現,讓我們可以用類似同步的方式來撰寫異步程式碼,提升了程式的可讀性。例如:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('發生錯誤:', error);
}
}相比之下,使用 Promise.then() 的寫法則是:
function fetchData() {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('發生錯誤:', error);
});
}從上述例子可以看出,async/await 讓程式碼結構更接近同步邏輯,減少了巢狀結構,提升了可讀性。然而,Promise.then() 在非 async 的環境中仍然適用,且在某些情境下可能更為直觀。
Callback Hell 問題
在使用 Promise.then() 時,如果多個異步操作有依賴關係,可能會導致 Callback Hell(回調地獄)。當回調函式過度巢狀時,程式碼變得難以閱讀與維護。例如:
function fetchUserData(userId) {
fetch(`https://api.example.com/user/${userId}`)
.then(response => response.json())
.then(user => {
fetch(`https://api.example.com/orders/${user.id}`)
.then(response => response.json())
.then(orders => {
fetch(`https://api.example.com/order-details/${orders[0].id}`)
.then(response => response.json())
.then(orderDetails => {
console.log('訂單詳細資料:', orderDetails);
})
.catch(error => console.error('獲取訂單詳情失敗:', error));
})
.catch(error => console.error('獲取訂單失敗:', error));
})
.catch(error => console.error('獲取使用者失敗:', error));
}這種嵌套的 .then() 結構會導致:
- 難以閱讀與維護:每個異步操作都巢狀在前一個
.then()內部,增加了理解成本。 - 錯誤處理複雜:每一層
.then()都可能發生錯誤,處理起來相當麻煩。
如何用 async/await 解決 Callback Hell?
async/await 可以讓程式碼變得更直覺,避免過度巢狀:
async function fetchUserData(userId) {
try {
const userResponse = await fetch(`https://api.example.com/user/${userId}`);
const user = await userResponse.json();
const ordersResponse = await fetch(`https://api.example.com/orders/${user.id}`);
const orders = await ordersResponse.json();
const orderDetailsResponse = await fetch(`https://api.example.com/order-details/${orders[0].id}`);
const orderDetails = await orderDetailsResponse.json();
console.log('訂單詳細資料:', orderDetails);
} catch (error) {
console.error('發生錯誤:', error);
}
}這樣的寫法讓程式碼結構更清晰,且可以透過 try…catch 統一處理錯誤,減少 Callback Hell 的問題。
錯誤處理
在使用 async/await 時,我們通常透過 try…catch 來進行錯誤處理,這使得錯誤處理邏輯更為集中:
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
} catch (error) {
console.error('發生錯誤:', error);
}
}而使用 Promise.then() 時,則是透過 .catch() 來捕捉錯誤:
function fetchData() {
fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
})
.catch(error => {
console.error('發生錯誤:', error);
});
}需要注意的是,await 會等待 Promise 解決後再繼續執行,這意味著它會暫停所在的 async 函式的執行;而 Promise.then() 則是在將回調函式加入回調鏈後,繼續執行當前函式。
執行順序
使用 await 時,需要注意可能導致的順序執行問題。例如,以下程式碼會依次等待每個 fetch 完成,導致總耗時增加:
async function fetchData() {
const data1 = await fetch(url1);
const data2 = await fetch(url2);
// 處理 data1 和 data2
}為了提高效率,我們可以使用 Promise.all 來並行執行多個異步操作:
async function fetchData() {
const [data1, data2] = await Promise.all([fetch(url1), fetch(url2)]);
// 處理 data1 和 data2
}這樣可以同時發送多個請求,縮短總的執行時間。
總結
為了更清楚地比較 async/await 與 Promise 的差異,我們可以用表格來整理它們的優缺點:

以上就是今天的分享,我們下篇文章見 👋🏻