Async/Await 與 Promise 的深度解析
一、基本概念
1. Promise
Promise 是 ES6 引入的異步編程解決方案,表示一個異步操作的最終完成(或失敗)及其結果值。
function fetchData() {return new Promise((resolve, reject) => {setTimeout(() => resolve('數據獲取成功'), 1000);}); }fetchData().then(data => console.log(data)).catch(error => console.error(error));
2. Async/Await
Async/Await 是 ES2017 (ES8) 引入的語法糖,基于 Promise 的更高層抽象,使異步代碼看起來像同步代碼。
async function getData() {try {const data = await fetchData();console.log(data);} catch (error) {console.error(error);} }
二、核心區別
特性 | Promise | Async/Await |
---|---|---|
代碼結構 | 鏈式調用(.then().catch()) | 同步寫法(try-catch 塊) |
可讀性 | 嵌套多時較難閱讀 | 線性執行,更易理解 |
調試 | 調試.then()鏈較困難 | 可以像同步代碼一樣調試 |
錯誤處理 | 必須使用.catch() | 可以使用try-catch |
返回值 | 總是返回Promise | async函數返回Promise |
流程控制 | 需要手動鏈接多個Promise | 可以用普通控制結構(for, if等) |
三、Async/Await 的優勢
1. 代碼更簡潔直觀
// Promise方式 function getUserAndPosts(userId) {return fetchUser(userId).then(user => fetchPosts(user.id)).then(posts => console.log(posts)).catch(error => console.error(error)); }// Async/Await方式 async function getUserAndPosts(userId) {try {const user = await fetchUser(userId);const posts = await fetchPosts(user.id);console.log(posts);} catch (error) {console.error(error);} }
2. 更自然的錯誤處
// 傳統Promise錯誤處理可能遺漏 fetchData().then(data => process(data))// 忘記添加catch會導致靜默失敗// Async/Await強制更安全的寫法 async function safeFetch() {try {const data = await fetchData();return process(data);} catch (error) {console.error('處理失敗:', error);throw error; // 可選擇重新拋出} }
3. 更簡單的流程控制
// 順序執行多個異步操作 async function sequentialOps() {const result1 = await operation1();const result2 = await operation2(result1);return operation3(result2); }// 條件執行 async function conditionalOp(shouldFetch) {if (shouldFetch) {return await fetchData();}return cachedData(); }// 循環中的異步操作 async function processItems(items) {for (const item of items) {await processItem(item); // 順序處理} }
四、使用注意事項
1. 常見誤區
// 錯誤1:忘記await async function oops() {const data = fetchData(); // 缺少await,data將是Promise對象console.log(data); // 輸出Promise而非結果 }// 錯誤2:過度順序化 async function slowOps() {const a = await getA(); // 等待const b = await getB(); // 繼續等待(如果無依賴關系應該并行)// 應該改為:// const [a, b] = await Promise.all([getA(), getB()]); }
2. 性能優化
// 并行執行獨立操作 async function parallelOps() {const [user, posts] = await Promise.all([fetchUser(),fetchPosts()]);return { user, posts }; }
3. 頂層Await
ES2022 支持在模塊頂層使用 await:
// module.js const data = await fetchData(); export default data;
五、如何選擇
-
使用Async/Await當:
-
需要順序執行多個異步操作
-
需要更清晰的錯誤處理
-
代碼可讀性是首要考慮
-
-
使用Promise當:
-
需要更精細的控制流(如同時觸發多個操作)
-
需要直接操作Promise(如Promise.race)
-
在不能使用async/await的環境(如某些舊瀏覽器)
-
六、實際應用示例
1. API請求處理
async function fetchUserWithPosts(userId) {try {const user = await api.get(`/users/${userId}`);const posts = await api.get(`/users/${userId}/posts`);return { ...user, posts };} catch (error) {if (error.response?.status === 404) {throw new Error('用戶不存在');}throw error;} }
2. 數據庫事務
async function transferFunds(senderId, receiverId, amount) {const connection = await db.getConnection();try {await connection.beginTransaction();await connection.query('UPDATE accounts SET balance = balance - ? WHERE id = ?',[amount, senderId]);await connection.query('UPDATE accounts SET balance = balance + ? WHERE id = ?',[amount, receiverId]);await connection.commit();} catch (error) {await connection.rollback();throw error;} finally {connection.release();} }
Async/Await 不是替代 Promise 的技術,而是基于 Promise 的更優雅的語法糖。理解兩者關系后,可以根據場景靈活選擇或混合使用。