async/await 是 Promise 的语法封装而非新语法糖,它通过自动包装返回值为 Promise、暂停执行而不阻塞主线程、强制 try/catch 错误处理及需配合 Promise.all 实现并发等机制,简化异步流程但不改变事件循环本质。

async/await 不是新语法糖,而是 Promise 的语法封装;它不能替代 Promise,但能显著降低回调嵌套和错误处理的复杂度。
async 函数本质是返回 Promise 的函数
声明一个 async 函数,等价于手动包装一个返回 Promise 的函数。调用它总会得到一个 Promise 实例,哪怕你 return 42,它也会被自动包装成 Promise.resolve(42)。
常见误解:以为 async 让函数“变同步”了——其实它只是让 await 可以暂停函数执行(仅限当前函数体),底层仍是事件循环驱动。
-
async函数内部遇到await会暂停,把控制权交还给事件循环,不阻塞主线程 - 如果
await后面不是Promise,会自动用Promise.resolve()包装 - 函数内抛出异常,等价于返回
Promise.reject(err)
await 只能在 async 函数内部使用
直接在顶层或普通函数里写 await 会报 SyntaxError: await is only valid in async functions。这是语法限制,不是运行时错误。
立即学习“Java免费学习笔记(深入)”;
常见场景应对方式:
- 模块顶层需等待:用
(async () => { ... })()立即执行 - 事件处理器中:把 handler 声明为
async function handleClick() { ... } - 循环中逐个 await:注意这会串行执行;想并发请用
Promise.all([p1, p2, p3])
async function fetchUsers() {
try {
const res = await fetch('/api/users');
const users = await res.json();
return users;
} catch (err) {
console.error('Fetch failed:', err);
throw err;
}
}
错误处理必须用 try/catch,不能只靠 .catch()
await 后的 Promise 被 reject,会直接抛出异常,不会像 .then().catch() 那样隐式传递。漏写 try/catch 就会导致未捕获异常(Uncaught (in promise))。
特别注意:
-
await Promise.reject('oops')会立即触发catch块,不是“跳过后续代码”而是中断当前 async 函数执行流 - 多个
await连续写时,任一失败都会终止后续 await,除非你对每个都单独 try/catch - 想忽略某个请求失败?得显式写
await something().catch(() => {})或用空数组兜底
await 处理并发请求:别误用 for 循环
写 for (const url of urls) { await fetch(url); } 是串行请求,总耗时 ≈ 所有请求时间之和。真正并发要先发所有请求,再统一 await。
正确做法:
- 并发全部发起:
const promises = urls.map(u => fetch(u)) - 等全部完成:
const responses = await Promise.all(promises) - 若允许部分失败,用
Promise.allSettled()替代Promise.all()
async function fetchAll(urls) {
const promises = urls.map(url =>
fetch(url).then(r => r.json()).catch(() => null)
);
return await Promise.all(promises);
}
最易被忽略的一点:await 不会“等整个异步链”,它只等紧跟着的那个 Promise 完成。如果你忘了链式调用中某处没 return,后续 await 就可能等错对象——比如漏了 return 导致 await 等到 undefined,再被包装成已 resolve 的 Promise,逻辑就悄悄跑偏了。











