异步编程的演进
JavaScript 的异步编程经历了几个阶段的演进:
回调函数时代
// 获取用户信息,然后获取订单
getUser(function(user) {
getOrders(user.id, function(orders) {
console.log(orders);
});
});
问题:回调地狱,代码难以维护。
Promise 时代
getUser()
.then(user => getOrders(user.id))
.then(orders => console.log(orders))
.catch(err => console.error(err));
问题:链式调用虽然改善了回调地狱,但仍然不够直观。
async/await 时代
async function fetchUserOrders() {
try {
const user = await getUser();
const orders = await getOrders(user.id);
console.log(orders);
} catch (err) {
console.error(err);
}
}
async/await 让异步代码看起来像同步代码,更加直观易读。
async/await 基础
async 函数
async 函数总是返回一个 Promise:
async function foo() {
return 'hello';
}
foo().then(console.log); // 'hello'
// 等价于
function foo() {
return Promise.resolve('hello');
}
await 表达式
await 会暂停函数执行,等待 Promise 解决:
async function example() {
const result = await Promise.resolve('done');
console.log(result); // 'done'
}
常见用法
顺序执行
async function sequential() {
const a = await Promise.resolve(1);
const b = await Promise.resolve(2);
const c = await Promise.resolve(3);
return a + b + c; // 6
}
并行执行
async function parallel() {
const [a, b, c] = await Promise.all([
Promise.resolve(1),
Promise.resolve(2),
Promise.resolve(3)
]);
return a + b + c; // 6
}
错误处理
async functionWithErrorHandling() {
try {
const result = await riskyOperation();
return result;
} catch (error) {
console.error('出错了:', error);
// 可以选择:
// 1. 返回默认值
return null;
// 2. 抛出新错误
throw new Error('处理失败');
// 3. 返回错误信息
return { error: true, message: error.message };
}
}
最佳实践
- 始终使用 try/catch:处理可能的错误
- 善用 Promise.all:并行执行独立的异步操作
- 避免过度 await:不需要等待的就不要 await
- 循环中使用 Promise.all:而不是 for 循环加 await
// 不推荐
for (const item of items) {
await processItem(item);
}
// 推荐
await Promise.all(items.map(item => processItem(item)));
总结
async/await 是 JavaScript 异步编程的重大改进,它让异步代码更加简洁易读。掌握 async/await 是每个前端开发者的必备技能。