async/await 原理与实践
1. 核心原理
async/await 是 ES8 引入的语法糖,其本质是 Generator 函数 + 自动执行器 的封装。
- async: 将函数标记为异步,确保函数返回一个
Promise。
- await: 暂停代码执行,等待右侧 Promise 解决(resolve),并将解包后的结果作为表达式的值。
它让异步代码看起来像同步代码,解决了 Promise 链式调用(.then().then())带来的语义不连贯问题。
2. 执行顺序分析 (非常重要)
面试中常考代码输出顺序。
console.log('script start');
async function async1() {
console.log('async1 start');
await async2();
console.log('async1 end');
}
async function async2() {
console.log('async2');
}
async1();
console.log('script end');
解析:
script start (宏任务)
async1 开始执行 -> async1 start
- 遇到
await async2() -> 执行 async2 (同步) -> 输出 async2
- 关键点:
await 后面的代码(console.log('async1 end'))被放入微任务队列,跳出 async1 函数。
script end (宏任务继续)
- 宏任务执行完毕,检查微任务队列 -> 执行
async1 剩余代码 -> 输出 async1 end
3. 错误处理
这也是相比 Promise 链的一大优势,可以使用标准的 try/catch。
async function fetchUser() {
try {
const user = await getUser();
const posts = await getPosts(user.id);
} catch (err) {
// 捕获 getUser 或 getPosts 中的 reject
console.error(err);
}
}
4. 并行与串行 (性能优化)
陷阱:不要在循环中无意地串行使用 await。
// ❌ 串行 (慢)
async function serial() {
const a = await fetchA(); // 等待 A 完成
const b = await fetchB(); // 再请求 B
}
// ✅ 并行 (快)
async function parallel() {
const pA = fetchA();
const pB = fetchB();
const a = await pA;
const b = await pB;
}
// ✅ 使用 Promise.all (推荐)
const [a, b] = await Promise.all([fetchA(), fetchB()]);
5. 面试加分项
- 顶层 await: ES2022 允许在模块顶层使用
await,无需包裹在 async 函数中。
- async 函数返回值: 总是返回 Promise。如果不报错且返回非 Promise 值,会通过
Promise.resolve 包装。