一、核心概念:async/await 与 Promise 的关系
1. 本质:
async/await是 Promise 的语法糖,使异步代码看起来像同步代码。async函数返回一个 Promise,await用于等待 Promise resolve/reject。
2. 对比传统异步写法:
// Promise 写法
fetchData().then(res => {
return processData(res);
}).then(result => {
console.log(result);
}).catch(err => {
console.error(err);
});
// async/await 写法(更简洁)
async function fetchAndProcess() {
try {
const res = await fetchData();
const result = await processData(res);
console.log(result);
} catch (err) {
console.error(err);
}
}
二、async 函数的返回值
async函数始终返回一个 Promise:async function fn() { return 123; } fn().then(res => console.log(res)); // 输出: 123- 若返回非 Promise 值,会自动包装为
Promise.resolve(值);若抛出错误,等价于Promise.reject(错误)。
三、await 的使用规则
1. 必须在 async 函数中使用:
async function demo() {
const data = await fetch('api'); // ✅ 合法
}
2. 等待 Promise 或普通值:
async function demo() {
const num = await 100; // num = 100(普通值会被包装为 resolved Promise)
const user = await fetchUser(); // 等待 Promise resolve
}
3. 错误处理:
- 使用
try/catch捕获单个await的错误:async function demo() { try { const data = await fetchData(); } catch (err) { console.error('获取数据失败', err); } } - 多个
await可共用一个try/catch:async function demo() { try { const res1 = await fetch1(); const res2 = await fetch2(); } catch (err) { console.error('任一请求失败', err); } }
四、并行异步操作:Promise.all vs await
1. 串行执行(逐个等待):
async function serial() {
const res1 = await fetch1();
const res2 = await fetch2(); // 等待 res1 完成后执行
return [res1, res2];
}
2. 并行执行(同时等待):
async function parallel() {
const p1 = fetch1();
const p2 = fetch2();
const [res1, res2] = await Promise.all([p1, p2]);
return [res1, res2];
}
优势:并行执行可减少总体耗时,适用于不依赖前置结果的请求。
五、async/await 中的错误冒泡
- 未捕获的错误会向上抛出:
async function fn1() { await fn2(); // 若 fn2 抛出错误,会被 fn1 的 try/catch 捕获 } async function demo() { try { await fn1(); } catch (err) { console.error('全局错误捕获', err); } }
六、问题
1. async/await 如何处理 Promise 拒绝
答:
- 使用
try/catch捕获await后的错误:const data = await fetchData().catch(err => handleErr(err)); - 或在
async函数中用try/catch包裹:const data = await (async () => { try { return await fetchData(); } catch (err) { return defaultData; } })();
2. 问:async/await 与 Generator 函数的区别?
答:
async/await是 ES7 标准,语法更简洁,自动处理 Promise。- Generator 需手动调用
next(),需配合co库使用(已被 async/await 替代)。
3. 问:如何中断正在执行的 async 函数?
答:
- 使用
AbortController(Web API):const controller = new AbortController(); async function fetchWithTimeout() { setTimeout(() => controller.abort(), 5000); // 5秒后中断 try { const res = await fetch('api', { signal: controller.signal }); return res; } catch (err) { if (err.name === 'AbortError') { console.log('请求已取消'); } } }
七、性能与注意事项
- 避免过度等待:
- 能并行的请求不要串行,用
Promise.all优化效率。
- 能并行的请求不要串行,用
- 错误边界:
- 重要业务逻辑建议每个
await都包裹try/catch,避免一个错误中断整个流程。
- 重要业务逻辑建议每个
- 兼容性:
- 低版本浏览器需引入
regenerator-runtime垫片。
- 低版本浏览器需引入