async/await 是 Promise 的语法封装而非新语法糖,async 函数自动将返回值包装为 Promise,await 只能在 async 函数内使用,需注意串行与并发区别及错误处理机制。

Async/await 不是新语法糖,而是 Promise 的语法封装,它本身不改变异步行为,但能显著降低回调嵌套和 .then() 链的维护成本。
async 函数必须显式返回 Promise
声明为 async 的函数,无论内部是否 await,其返回值都会被自动包装成 Promise。这意味着:
- 直接
return 42→ 实际返回Promise.resolve(42) -
return Promise.reject(new Error())不会再被包装,原样传出 - 如果忘记
await一个 async 函数调用,你拿到的是一个 pending 的 Promise,不是结果
async function getValue() {
return "done";
}
console.log(getValue()); // Promise {}
console.log(await getValue()); // "done"
await 只能在 async 函数内使用
试图在普通函数或顶层作用域中写 await 会触发 SyntaxError: await is only valid in async functions。常见误用场景包括:
- 在
if或for块里直接await(没包 async 函数) - Node.js 14.8+ 支持顶层 await,但仅限 ES 模块(
type: "module"),CommonJS 中仍非法 - React 事件处理器如
onClick={() => await handleSubmit()}会报错,必须写成onClick={async () => {...}}
错误处理:不要只靠 try/catch,也要检查 rejected 状态
await 会让 rejected Promise 抛出异常,所以 try/catch 是主流做法。但要注意:
-
await Promise.all([p1, p2])任一失败即整体 reject,无法获知哪个出错 —— 改用Promise.allSettled()更稳妥 - 对可能为
null或非 Promise 的值调用await不会报错,但无意义(await 123直接返回123) - 未捕获的 Promise rejection 会触发
unhandledrejection事件,在 Node.js 中可能导致进程退出
async function fetchBoth() {
try {
const [a, b] = await Promise.allSettled([
fetch("/api/user"),
fetch("/api/posts")
]);
if (a.status === "fulfilled") console.log(a.value);
if (b.status === "rejected") console.error(b.reason);
} catch (e) {
// 这里不会捕获 Promise.allSettled 的 rejection
}
}
性能陷阱:await 并不自动并发,顺序写 = 串行执行
这是最常被忽略的一点:await 是阻塞当前 async 函数执行流的,但不阻塞整个线程。连续写多个 await 就是串行,不是并行:
- ❌ 错误示范(耗时 = t1 + t2):
const a = await fetch("/a"); const b = await fetch("/b"); - ✅ 正确做法(耗时 ≈ max(t1, t2)):
const [a, b] = await Promise.all([fetch("/a"), fetch("/b")]); - 若需按序处理但又想提前发起请求,先发请求再
await:const promiseA = fetch("/a"); const promiseB = fetch("/b"); const a = await promiseA; const b = await promiseB;
真正难的不是写 async/await,而是判断哪些操作该并发、哪些必须串行、哪些根本不需要 await —— 这些决定直接影响响应时间和资源利用率。










