async/await 是 JavaScript 处理 Promise 的标准化方式,不改变异步本质但降低回调嵌套与错误处理复杂度;async 函数自动包装返回值为 Promise,await 仅限 async 函数内使用且不阻塞主线程。

Async/await 不是新语法糖,而是 JavaScript 处理 Promise 的标准化方式;它本身不改变异步本质,但能显著降低回调嵌套和错误处理的复杂度。
async 函数必须显式返回 Promise
声明为 async 的函数会自动包装返回值为 Promise。即使你写 return 42,实际返回的是 Promise.resolve(42)。这意味着:
- 不能靠
return直接跳出异步流程(比如想提前终止请求) - 若函数内部抛出错误,会变成 rejected Promise,需用
try/catch或.catch()捕获 - 如果忘记加
await调用另一个async函数,你拿到的是一个 pending Promise,不是结果
await 只能在 async 函数内使用
await 是语法关键字,不是函数,也不能在顶层作用域或普通回调里用。常见误用场景包括:
- 在
forEach回调中写await→ 实际上不会等待,因为forEach不支持异步迭代 - 在
setTimeout或事件监听器中直接await→ 报错SyntaxError: await is only valid in async function - 想在模块顶层 await 一个初始化操作 → 需改用
top-level await(仅 ES 模块且环境支持,如 Node.js 14.8+ 或现代浏览器)
await 会阻塞当前 async 函数,但不阻塞主线程
这是最容易误解的一点:await 暂停的是当前 async 函数的执行上下文,引擎会把控制权交还给事件循环。例如:
async function load() {
console.log('start');
await fetch('/api/data'); // 这里暂停,但 UI 仍可响应
console.log('done');
}
关键影响:
- 多个
await是串行的,想并发请用Promise.all([p1, p2])包一层再await - 没有超时机制,
await apiCall()可能永远卡住,生产环境应包裹AbortController或封装带 timeout 的 Promise - 调试时注意:断点停在
await后一行,不代表前面请求已完成,只是 microtask 已入队
真正麻烦的从来不是写 async/await,而是搞清哪些地方该等、哪些不该等,以及怎么让错误流自然落到你写的 catch 块里 —— 尤其当混合使用 .then() 和 await 时,拒绝路径容易意外丢失。









