async/await
async/await 是 JavaScript 中用來處理異步操作的語法糖,基於 Promise,讓異步程式碼看起來更像同步程式碼。這使得代碼更易讀、更易於理解,特別是在處理複雜的異步邏輯時。下面將詳細說明 async/await 的使用方式,包括基礎語法、錯誤處理、在迴圈中的使用,以及與 Promise 的結合。
1. 基本語法
1.1 async 關鍵字
async 關鍵字用於定義一個異步函式。異步函式會自動將返回值包裝在一個 Promise 物件中。
async function exampleFunction() {
return "Hello, world!";
}
exampleFunction().then(result => console.log(result)); // 輸出 "Hello, world!"
即使直接返回一個值,async 函式也會返回一個已完成狀態的 Promise。
1.2 await 關鍵字
await 關鍵字只能在 async 函式內部使用,用來等待一個 Promise 完成。當 await 等待的 Promise 完成後,會返回該 Promise 的結果。如果 Promise 被拒絕(rejected),await 會拋出異常。
async function fetchData() {
let response = await fetch('https://api.example.com/data');
let data = await response.json();
console.log(data);
}
fetchData();
await 暫停函式的執行,直到 fetch 的 Promise 完成並返回結果。這使得 fetchData 函式內的代碼看起來像同步的。
2. 錯誤處理
async/await 允許你使用傳統的 try...catch 結構來捕獲異步操作中的錯誤,這比 Promise 的 catch 方法更加直觀。
async function fetchData() {
try {
let response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch error:', error);
}
}
fetchData();
try 區塊中的代碼嘗試執行,如果 await 等待的 Promise 被拒絕或拋出異常,catch 區塊會捕獲並處理錯誤。
3. 在迴圈中使用 async/await
當需要對多個異步操作依次執行時,async/await 可以與迴圈結合使用。這樣可以確保每個異步操作在前一個操作完成後才開始執行。
async function fetchMultipleUrls(urls) {
for (let url of urls) {
let response = await fetch(url);
let data = await response.json();
console.log(data);
}
}
let urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
fetchMultipleUrls(urls);
這個例子中,每個 fetch 操作會等待前一個操作完成後再開始,這保證了按順序處理每個請求。
4. 並行執行異步操作
儘管 await 使代碼看起來像是同步執行,但有時你可能希望並行執行多個異步操作,而不是一個接一個地執行。你可以結合 Promise.all 與 async/await 來達成這一目的。
async function fetchMultipleUrls(urls) {
let fetchPromises = urls.map(url => fetch(url));
let responses = await Promise.all(fetchPromises);
let dataPromises = responses.map(response => response.json());
let allData = await Promise.all(dataPromises);
console.log(allData);
}
let urls = ['https://api.example.com/data1', 'https://api.example.com/data2'];
fetchMultipleUrls(urls);
在這個範例中,所有的 fetch 請求會並行執行,然後等待所有請求完成後,再處理每個回應。
5. 與傳統 Promise 的比較
雖然 async/await 是基於 Promise 的,但它提供了更簡潔的語法,讓異步代碼更加可讀。
傳統的 Promise 語法:
fetch('https://api.example.com/data')
.then(response => {
if (!response.ok) {
throw new Error('Network response was not ok');
}
return response.json();
})
.then(data => console.log(data))
.catch(error => console.error('Fetch error:', error));
使用 async/await 的語法:
async function fetchData() {
try {
let response = await fetch('https://api.example.com/data');
if (!response.ok) {
throw new Error('Network response was not ok');
}
let data = await response.json();
console.log(data);
} catch (error) {
console.error('Fetch error:', error);
}
}
fetchData();
async/await 讓異步代碼看起來更像是線性、同步的代碼,而不是嵌套的回調函式。
6. 與同步代碼的結合
雖然 async/await 用於異步操作,但你仍然可以將同步代碼與其結合。await 只會影響到它所等待的 Promise,其他同步代碼不會受到影響。
async function exampleFunction() {
console.log("Start");
let promise = new Promise((resolve) => setTimeout(resolve, 2000));
await promise;
console.log("End after 2 seconds");
}
exampleFunction();
async/await 與同步代碼的結合。
總結
async/await 是處理 JavaScript 異步操作的強大工具。它建立在 Promise 的基礎上,提供了更簡潔、更直觀的方式來編寫和管理異步代碼。無論是在處理簡單的 API 請求,還是管理複雜的異步邏輯,async/await 都能讓你的代碼更加清晰和易於維護。