async 和 await 是 Promise 的语法糖,async 函数自动返回 Promise,await 只能用于 async 函数内且等待 thenable 对象;错误处理需兼顾 try/catch 与全局 unhandledrejection 监听。

async 和 await 不是新魔法,而是 Promise 的语法糖——它不改变异步本质,只改写你跟异步打交道的方式。用对了,代码像同步一样直白;用错了,反而更难 debug。
async 函数为什么必须返回 Promise?
因为 async 关键字一加,JavaScript 就自动给你套一层 Promise.resolve()。哪怕你 return 123,实际返回的是 Promise.resolve(123)。
这决定了:你不能在普通函数里用 await,也不能把 await 放在顶层(ES2022+ 才支持顶层 await,且仅限模块)。
- 常见错误现象:
await is only valid in async functions—— 忘记给外层函数加async - 使用场景:封装 API 调用、文件读取、数据库查询等耗时操作
- 性能影响:每次
async函数调用都会创建一个 Promise 对象,高频小函数慎用(比如循环里逐个await)
await 等待的到底是什么?
await 只认“thenable”对象——也就是有 .then() 方法的对象。绝大多数时候就是 Promise,但也可以是自定义类(只要实现了 then)。
- 容易踩的坑:直接
await一个普通值(如await "hello")不会报错,但会立刻 resolve,相当于没等 - 兼容性注意:Node.js 7.6+、Chrome 55+、Firefox 52+ 均支持;IE 完全不支持,需 Babel 转译
- 典型误用:
await setTimeout(() => {}, 1000)——setTimeout返回的是 timer ID(数字),不是 Promise,必须手动包装
如何避免 await 串行阻塞?
连续写多个 await 就是串行执行,前一个不结束,后一个不动。但很多请求彼此无关,完全可以并行。
- 正确做法:先发请求,再
await Promise.all([p1, p2, p3]) - 错误示范:
const a = await fetch('/a'); const b = await fetch('/b');—— 总耗时 ≈ a + b - 进阶技巧:用
Promise.allSettled()替代Promise.all(),避免单个失败导致全部中断 - 注意点:
Promise.all中任意一个 reject,整个就 reject,即使你后面写了try/catch,也得包住整个all调用
错误处理为什么不能只靠 try/catch?
try/catch 能捕获被 reject 的 Promise,但对未处理的 Promise rejection(比如忘记 await 或漏写 catch)无能为力——这类错误会变成 unhandledrejection,可能静默失败。
- 真实问题:接口 401 报错后页面没提示,控制台只有一行
Unhandled promise rejection - 实操建议:全局监听
window.addEventListener('unhandledrejection', ...)(浏览器)或process.on('unhandledRejection', ...)(Node.js)做兜底 - 关键细节:每个
await后都应有明确的错误分支,或确保上层统一 catch,不要依赖“反正有人会处理”
await 到底卡在哪一层——是网络超时?后端没响应?还是 Promise 被忘了 resolve?遇到问题先查微任务队列状态,再看 reject 是否被吞掉。










