一、核心知识点(30 分钟吃透)
1. async/await 核心本质
async/await是 Promise 的语法糖,底层完全基于 Promise 实现,目的是将异步代码写成 "同步风格",彻底摆脱回调嵌套和链式调用的冗余。- 核心规则:
async修饰函数:函数返回值自动包装为 Promise(即使返回普通值,也会变成fulfilled状态的 Promise);await只能在async函数内使用:暂停函数执行,等待右侧 Promise 状态变更(成功 / 失败),再恢复执行并返回 Promise 的结果;- 错误处理:
await后的 Promise 失败时,需用try/catch捕获(否则会导致整个async函数返回rejected状态的 Promise)。
2. 与 Promise 对比
表格
| 特性 | Promise 链式调用 | async/await |
|---|---|---|
| 代码风格 | 链式 then/catch,线性但冗余 | 同步风格,可读性更高 |
| 错误处理 | 统一 catch 捕获 | try/catch 捕获(更符合直觉) |
| 流程控制 | 多层嵌套需链式传递 | 可直接用 if/for 等同步逻辑 |
二、实战练习:封装 async/await 版请求(40 分钟必练)
案例 1:基础封装(兼容成功 / 失败)
js
// 1. 封装基础请求函数(返回Promise)
function request(url) {
return new Promise((resolve, reject) => {
setTimeout(() => {
const mockData = { code: 200, data: `请求${url}成功` };
// 模拟50%成功率
Math.random() > 0.5
? resolve(mockData)
: reject(new Error(`请求${url}失败`));
}, 1000);
});
}
// 2. async/await 封装业务请求(同步风格)
async function fetchData() {
// 加载状态(如显示loading)
console.log("请求中...");
try {
// 暂停执行,等待请求结果
const userRes = await request("/api/user");
console.log("用户数据:", userRes);
// 基于上一个请求结果,发起下一个请求(同步逻辑更直观)
const orderRes = await request(`/api/order?userId=${userRes.data.id || 1}`);
console.log("订单数据:", orderRes);
return { user: userRes, order: orderRes }; // 返回值自动包装为Promise
} catch (err) {
// 捕获任意await的错误
console.error("请求失败:", err.message);
// 错误兜底(可选)
return { code: 500, msg: "请求异常" };
} finally {
// 无论成败,关闭加载
console.log("请求结束,关闭loading");
}
}
// 3. 调用async函数(返回Promise,可链式调用)
fetchData().then(res => console.log("最终结果:", res));
案例 2:批量请求(Promise.all + async/await)
js
// 并行请求多个接口,等待所有请求完成
async function fetchBatchData() {
try {
// 并行执行,总耗时取最长的请求(而非串行叠加)
const [userRes, goodsRes, orderRes] = await Promise.all([
request("/api/user"),
request("/api/goods"),
request("/api/order")
]);
console.log("批量请求结果:", { userRes, goodsRes, orderRes });
} catch (err) {
console.error("任意一个请求失败:", err);
}
}
fetchBatchData();
三、核心面试题 + 标准答案(20 分钟背会)
面试题:async/await 的原理是什么?相比 Promise 有哪些优点?
标准答案(高级工程师视角,精简且有深度)
1. async/await 的底层原理
async/await是 Generator 函数 + Promise 的语法糖 (ES7 引入),由 JS 引擎自动实现 Generator 的执行器逻辑:async函数:本质是返回一个 Promise 的 Generator 函数的语法糖,函数执行时会自动创建迭代器并执行;await关键字:等价于 Generator 中的yield,暂停函数执行,等待右侧 Promise 状态变更后,将结果作为yield的返回值,恢复函数执行;- 错误处理:底层复用 Promise 的错误捕获机制,
await后的 Promise 失败会触发try/catch,本质是捕获 Promise 的rejected状态。
2. async/await 相比 Promise 的核心优点
- 代码可读性极致提升:将异步代码从 "链式 then/catch" 转为 "同步风格",尤其是多层异步嵌套(如接口依赖请求),代码逻辑更直观,维护成本降低 50%+;
- 流程控制更灵活:可直接使用 if/for/while 等同步流程控制语句(如 "请求 A 成功才请求 B,否则终止"),而 Promise 链式调用需通过 return 控制,逻辑冗余;
- 错误处理更符合直觉 :用
try/catch捕获单个 / 多个异步错误,可精准控制错误范围(如仅捕获某一个 await 的错误),而 Promise 链式调用的 catch 会捕获所有环节错误,需额外区分; - 调试更友好 :断点可直接停在
await行,同步调试异步代码,而 Promise 链式调用需在 then 回调内断点,调试体验差。
3. 实战避坑点(面试加分)
await会阻塞当前async函数执行,非必要时不要串行请求(如无依赖的多接口请求,用Promise.all并行执行,提升性能);- 未用
try/catch包裹的await错误,会导致async函数返回rejected状态的 Promise,需全局捕获(如window.addEventListener('unhandledrejection', cb)); await右侧不仅可以是 Promise,也可以是普通值(直接返回该值),但实际开发中仅用于 Promise 等待。
四、错题整理模板(10 分钟完成)
表格
| 错题类型 | 错误代码 / 场景 | 错误原因 | 正确思路 / 知识点 |
|---|---|---|---|
| 串行请求性能问题 | 无依赖的多接口依次 await | 忽略并行请求优化 | 用 Promise.all 并行执行无依赖请求 |
| 错误捕获遗漏 | async 函数内未写 try/catch | await 失败导致函数返回 rejected Promise | 必须用 try/catch 捕获,或外部 catch |
| 语法错误 | 普通函数内使用 await | 忽略 await 仅能在 async 函数内使用 | 给外层函数添加 async 修饰 |
总结
- 核心考点:async/await 是 Promise 的语法糖,底层基于 Generator + Promise,核心优势是 "同步风格写异步";
- 实战重点 :掌握
try/catch错误处理、Promise.all并行请求优化,这是前端接口封装的核心技能; - 易错点:避免无意义的串行 await、不要遗漏错误捕获,这是面试中体现工程化思维的关键。