JavaScript 异步编程:从回调地狱到 async/await
异步编程是 JavaScript 的核心。本文介绍异步编程的发展历程。
回调函数
// 回调地狱
getUser(userId, (user) => {
getOrders(user.id, (orders) => {
getOrderDetails(orders[0].id, (details) => {
console.log(details);
});
});
});
问题:
- 嵌套层级深
- 错误处理困难
- 代码难以维护
Promise
// Promise 链式调用
getUser(userId)
.then(user => getOrders(user.id))
.then(orders => getOrderDetails(orders[0].id))
.then(details => console.log(details))
.catch(error => console.error(error));
Promise 基本用法
const promise = new Promise((resolve, reject) => {
setTimeout(() => resolve('成功'), 1000);
});
promise.then(result => console.log(result));
Promise 静态方法
// 全部完成
Promise.all([promise1, promise2, promise3])
.then(results => console.log(results));
// 任意完成
Promise.race([promise1, promise2, promise3])
.then(result => console.log(result));
// 全部完成(不论成功失败)
Promise.allSettled([promise1, promise2])
.then(results => console.log(results));
// 任意成功
Promise.any([promise1, promise2, promise3])
.then(result => console.log(result));
async/await
async function getUserDetails(userId) {
try {
const user = await getUser(userId);
const orders = await getOrders(user.id);
const details = await getOrderDetails(orders[0].id);
return details;
} catch (error) {
console.error(error);
}
}
并行执行
// ❌ 串行执行(慢)
const user = await getUser(id);
const orders = await getOrders(id);
// ✅ 并行执行(快)
const [user, orders] = await Promise.all([
getUser(id),
getOrders(id)
]);
错误处理
// try/catch
async function fetchData() {
try {
const data = await fetch('/api');
return data;
} catch (error) {
console.error(error);
return null;
}
}
// .catch()
fetch('/api')
.then(res => res.json())
.catch(error => console.error(error));
最佳实践
- 使用 async/await:比 Promise 链更易读
- 并行执行:使用 Promise.all 并行处理
- 错误处理:始终处理错误
- 避免回调地狱:使用 Promise 或 async/await
总结
从回调函数到 Promise 再到 async/await,JavaScript 异步编程越来越简洁。async/await 是目前最佳的异步编程方式。