深入理解 JavaScript 的 async/await

在我們之前討論的 Promise 和 setTimeout 的基礎上,async/await 是 JavaScript 中處理非同步操作的更高層次抽象。它提供了一種更直觀、更類似同步程式碼的方式來處理非同步操作。

async/await 的基本概念

  1. async 函式

    • 使用 async 關鍵字宣告的函式。
    • 總是返回一個 Promise。
    • 允許在其中使用 await 關鍵字。
  2. await 運算符

    • 只能在 async 函式內部使用。
    • 用於等待一個 Promise 解決(或拒絕)。
    • 暫停 async 函式的執行,直到 Promise 完成。

與 Promise 的關係

async/await 本質上是 Promise 的語法糖。它讓我們可以用更簡潔、更易讀的方式編寫基於 Promise 的程式碼。讓我們看一個例子來比較:

使用 Promise:

1
2
3
4
5
6
7
8
9
10
11
function fetchData() {
return fetch('https://api.example.com/data')
.then(response => response.json())
.then(data => {
console.log(data);
return data;
})
.catch(error => {
console.error('發生錯誤:', error);
});
}

使用 async/await:

1
2
3
4
5
6
7
8
9
10
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
const data = await response.json();
console.log(data);
return data;
} catch (error) {
console.error('發生錯誤:', error);
}
}

可以看到,async/await 版本的程式碼結構更加清晰,更像是同步程式碼的寫法。

async/await 與事件循環

雖然 async/await 讓程式碼看起來像是同步執行的,但實際上它仍然是非同步的。當遇到 await 時,函式會暫停執行,但不會阻塞整個程式。這與我們之前討論的事件循環機制密切相關:

  1. 同步程式碼優先執行。
  2. 遇到 await 時,程式會釋放控制權,允許其他程式碼執行。
  3. await 的 Promise 解決時,函式會在適當的時機恢復執行。

async/await 與 setTimeout

我們可以結合 async/await 和 setTimeout 來創建更易讀的延遲函式:

1
2
3
4
5
6
7
8
9
10
11
function delay(ms) {
return new Promise(resolve => setTimeout(resolve, ms));
}

async function delayedGreeting(name) {
console.log('開始等待...');
await delay(2000);
console.log(`你好,${name}!`);
}

delayedGreeting('小明');

這個例子展示了如何使用 async/await 來處理 setTimeout 創建的延遲,使得程式碼更加直觀。

async/await 的錯誤處理

async/await 提供了更直觀的錯誤處理方式。我們可以使用普通的 try/catch 語句:

1
2
3
4
5
6
7
8
9
10
11
12
async function fetchData() {
try {
const response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('網路回應不正確');
}
return await response.json();
} catch (error) {
console.error('發生錯誤:', error);
// 可以在這裡進行錯誤處理,例如顯示錯誤消息給用戶
}
}

這比使用 .catch() 方法更容易理解和維護。

注意事項

  1. 不要濫用 await:

    • 如果多個非同步操作之間沒有依賴關係,考慮使用 Promise.all() 同時執行它們。
  2. async 函式總是返回 Promise:

    • 即使你的函式看起來返回的是普通值,它實際上會被自動包裝成 Promise。
  3. 瀏覽器支援:

    • 大部分現代瀏覽器都支援 async/await,但在支援舊版瀏覽器時可能需要使用轉譯工具。

結論

async/await 是 JavaScript 中處理非同步操作的強大工具。它建立在 Promise 的基礎上,提供了更簡潔、更易讀的語法。通過結合我們之前討論的 Promise 和事件循環的知識,以及本文介紹的 async/await,你可以更有效地處理 JavaScript 中的非同步流程,寫出更加清晰、易維護的程式碼。