本专栏聚焦Promise的核心原理与高级应用,包含: ✓ Promise A+规范深度解读 ✓ 手写实现与源码分析 ✓ 异步编程设计模式 ✓ 性能调优与错误处理
适合有JavaScript基础,希望深入异步编程的开发者。我们将用最少的篇幅,讲透最核心的知识。
引言
在之前的文章中,我们学习了Promise的基础和原理实现。从中我们不难发现,即使是链式调用,处理复杂的异步流程仍然有些繁琐,我们来看下面的例子:
javascript
// Promise链式调用
fetchUser(userId)
.then(user => fetchOrders(user.id))
.then(orders => processOrders(orders))
.then(result => displayResult(result))
.catch(error => handleError(error))
.finally(() => cleanup());
在这种情况下,async/await语法应运而生,它让我们可以用同步的方式写异步代码:
javascript
// async/await版本
async function displayUserOrders(userId) {
try {
const user = await fetchUser(userId);
const orders = await fetchOrders(user.id);
const result = await processOrders(orders);
displayResult(result);
} catch (error) {
handleError(error);
} finally {
cleanup();
}
}
async:声明异步函数
基本语法
async 关键字用于声明一个异步函数:
javascript
// async函数声明
async function getUser() {
return { name: '张三', age: 25 };
}
// async函数表达式
const getData = async function() {
return '数据';
};
// async箭头函数
const fetchData = async () => {
return await fetch('/api/data');
};
// async方法
class UserService {
async getUser(id) {
// 异步操作
}
}
函数返回值
async 函数总是返回一个 Promise 。
javascript
async function basicReturn() {
return 42; // 等价于 Promise.resolve(42)
}
async function promiseReturn() {
return Promise.resolve('hello'); // 返回的Promise
}
async function throwError() {
throw new Error('失败'); // 等价于 Promise.reject(error)
}
await:等待Promise解决
基本使用
await 只能在 async 函数内部使用,它会暂停 async 函数的执行,等待Promise解决:
javascript
async function example() {
console.log('开始执行');
// await会暂停执行,直到Promise解决
const result = await fetchData();
console.log('数据获取完成:', result);
return result;
}
// 等价于
function examplePromise() {
console.log('开始执行');
return fetchData().then(result => {
console.log('数据获取完成:', result);
return result;
});
}
错误处理:try-catch的回归
同步风格的错误处理
javascript
// 传统Promise错误处理(分散)
fetchUser()
.then(user => {
return fetchOrders(user.id)
.catch(orderError => {
console.error('获取订单失败:', orderError);
return [];
});
})
.catch(userError => {
console.error('获取用户失败:', userError);
});
// async/await错误处理(集中)
async function getUserOrders() {
try {
const user = await fetchUser();
try {
const orders = await fetchOrders(user.id);
return orders;
} catch (orderError) {
console.error('获取订单失败:', orderError);
return []; // 返回默认值
}
} catch (userError) {
console.error('获取用户失败:', userError);
throw userError; // 重新抛出
}
}
// 更简洁的版本
async function getUserOrdersBetter() {
try {
const user = await fetchUser();
const orders = await fetchOrders(user.id);
return orders;
} catch (error) {
console.error('操作失败:', error);
// 根据错误类型处理
if (error.message.includes('用户')) {
throw new Error('用户相关操作失败');
}
return []; // 默认值
}
}
多await操作的错误处理
javascript
async function multipleOperations() {
// 方法1:分别处理每个await(粒度细)
let user;
try {
user = await fetchUser();
} catch (error) {
console.error('获取用户失败');
return null;
}
let orders;
try {
orders = await fetchOrders(user.id);
} catch (error) {
console.error('获取订单失败,但用户数据有效:', user);
orders = [];
}
// 方法2:统一处理(粒度粗)
try {
const user = await fetchUser();
const orders = await fetchOrders(user.id);
const products = await fetchProducts(orders);
return { user, orders, products };
} catch (error) {
console.error('某个步骤失败:', error);
// 无法区分哪个步骤失败
}
// 方法3:组合使用(推荐)
try {
const user = await fetchUser().catch(() => {
throw new Error('用户获取失败,终止流程');
});
const orders = await fetchOrders(user.id).catch(() => {
console.warn('订单获取失败,使用空数组');
return [];
});
// 即使orders为空,也继续执行
const analysis = await analyzeData(user, orders);
return analysis;
} catch (error) {
console.error('致命错误:', error);
return null;
}
}
停止和恢复执行
async/await 中真正起作用的是 await 。async 关键字只是一个标识符。我们可以看下面一个例子:
javascript
async function test() {
console.log(await Promise.resolve(1));
}
async function test2() {
console.log(await '2');
}
async function test3() {
console.log(3);
}
test();
test2();
test3();
上述代码的输出结果是:3 2 1 。因为JS运行时,在碰到 await 关键字时,会记录在哪里执行暂停。等待 await 后边的值可以用了,JS运行时会向消息队列中推送一个任务,这个任务会恢复函数执行。
结语
Promise 和 async/await 是JS异步编程的黄金组合:Promise 提供了底层的异步抽象和组合能力,async/await 提供了上层的语法糖,让异步代码更易读。对于文章中错误的地方或者有任何问题,欢迎在评论区留言讨论!