async/await 是 Promise 的语法封装,不改变异步本质但简化回调与错误处理;async 函数自动返回 Promise,await 暂停执行而不阻塞线程,需在 async 内使用,配合 try/catch 可清晰捕获 rejection。
async/await 不是新语法糖,而是 Promise 的语法封装,它本身不改变异步行为,但能显著降低回调嵌套和错误处理的复杂度。
声明为 async function 的函数,无论内部是否用 await,返回值都会被自动包装成 Promise。直接 return 42 等价于 return Promise.resolve(42);抛出错误等价于 return Promise.reject(err)。
常见错误:在 async 函数里忘记 await 调用另一个 async 函数,导致返回的是 pending Promise 而非实际值。
const data = await fetchUser();
const data = fetchUser(); // data 是 Promise,不是用户对象
await 只在 async 函数内有效,顶层 await 仅在模块作用域(ESM)或 REPL 中可用await 后面的表达式必须是 thenable(通常是 Promise),它会让 JS 引擎暂停当前 async 函数的执行,把控制权交还给事件循环,等 Promise settle 后再继续。这和同步阻塞完全不同。
使用场景:串行请求、依赖前序结果的逻辑、需要按顺序处理多个异步操作。
await 是串行的:await a(); await b(); 表示 b 等 a 完成后再开始Promise.all([a(), b()]),再 await 它await 后的 Promise 被 reject,会以异常形式抛出,可直接用 try/catch 捕获——这比链式调用中每个 .then() 后都接 .catch() 清晰得多。
容易踩的坑:只在最外层 try/catch,却忽略中间某个 await 实际上没被包裹。
async function load() {
try {
const user = await fetch('/user');
const posts = await fetch(`/posts?uid=${user.id}`);
return { user, posts };
} catch (err) {
console.error('加载失败:', err.message);
}
}await fetch('/user').catch(handleErr); —— 这样后续 await fetch(...) 仍可能抛未捕获异常catch 捕获的是 Promise rejection,不是同步 throw;若需区分网络错误、解析错误等,得靠检查 err.name 或响应状态码
真正难的从来不是写 async/await,而是判断哪些操作该串行、哪些该并发、哪些该降级,以及如何让错误提示对用户有意义——语法只是工具,决策才决定质量。