[Medium] 📄 Async/Await
💡 建議先閱讀 Promise 了解基礎概念
什麼是 async/await?
async/await 是 ES2017 (ES8) 引入的語法糖,建立在 Promise 之上,讓非同步程式碼看起來像同步程式碼,更容易閱讀和維護。
核心概念:
async函數總是回傳一個 Promiseawait只能在async函數內使用await會暫停函數執行,等待 Promise 完成
基本語法
async 函數
async 關鍵字讓函數自動回傳 Promise:
// 傳統 Promise 寫法
function fetchData() {
return Promise.resolve('資料');
}
// async 寫法(等價)
async function fetchData() {
return '資料'; // 自動包裝成 Promise.resolve('資料')
}
// 呼叫方式相同
fetchData().then((data) => console.log(data)); // '資料'
await 關鍵字
await 會等待 Promise 完成並回傳結果:
async function getData() {
const result = await Promise.resolve('完成');
console.log(result); // '完成'
}
Promise vs async/await 對比
範例 1:簡單的 API 請求
Promise 寫法:
function getUserData(userId) {
return fetch(`/api/users/${userId}`)
.then((response) => response.json())
.then((user) => {
console.log(user);
return user;
})
.catch((error) => {
console.error('錯誤:', error);
throw error;
});
}
async/await 寫法:
async function getUserData(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
const user = await response.json();
console.log(user);
return user;
} catch (error) {
console.error('錯誤:', error);
throw error;
}
}
範例 2:串聯多個非同步操作
Promise 寫法:
function processUserData(userId) {
return fetchUser(userId)
.then((user) => {
return fetchPosts(user.id);
})
.then((posts) => {
return fetchComments(posts[0].id);
})
.then((comments) => {
console.log(comments);
return comments;
})
.catch((error) => {
console.error('錯誤:', error);
});
}
async/await 寫法:
async function processUserData(userId) {
try {
const user = await fetchUser(userId);
const posts = await fetchPosts(user.id);
const comments = await fetchComments(posts[0].id);
console.log(comments);
return comments;
} catch (error) {
console.error('錯誤:', error);
}
}
錯誤處理
try/catch vs .catch()
async/await 使用 try/catch:
async function fetchData() {
try {
const response = await fetch('/api/data');
const data = await response.json();
return data;
} catch (error) {
console.error('請求失敗:', error);
// 可以在這裡處理不同類型的錯誤
if (error.name === 'NetworkError') {
// 處理網路錯誤
}
throw error; // 重新拋出或回傳預設值
}
}
混合使用(不推薦但有效):
async function fetchData() {
const response = await fetch('/api/data').catch((error) => {
console.error('請求失敗:', error);
return null;
});
if (!response) return null;
const data = await response.json();
return data;
}
多層 try/catch
針對不同階段的錯誤,可以使用多層 try/catch:
async function complexOperation() {
let user;
try {
user = await fetchUser();
} catch (error) {
console.error('取得使用者失敗:', error);
return null;
}
try {
const posts = await fetchPosts(user.id);
return posts;
} catch (error) {
console.error('取得文章失敗:', error);
return []; // 回傳空陣列作為預設值
}
}