async/await的核心是让异步代码像同步一样可读且非阻塞,需理清依赖、控制并发、统一错误处理、避免忘写await、滥用async、错误try/catch位置及未处理拒绝。

用 async 和 await 写异步逻辑,核心是让代码看起来像同步一样可读,同时保持非阻塞执行。关键不是“加个 async 就完事”,而是理清依赖、控制并发、处理错误、避免常见陷阱。
把 Promise 链改造成 await 序列
多个有先后依赖的异步操作(比如先登录,再拿 token 请求用户信息,再查订单),用 await 串起来比嵌套 .then() 清晰得多:
✅ 推荐写法:
async function loadUserProfile() {
try {
const loginRes = await login({ username, password });
const user = await fetchUser(loginRes.token);
const orders = await fetchOrders(user.id);
return { user, orders };
} catch (err) {
console.error('加载失败:', err.message);
throw err;
}
}
❌ 避免这样写(没错误处理 + 忘了 await):
立即学习“Java免费学习笔记(深入)”;
async function badExample() {
const loginRes = login({ username, password }); // ❌ 忘了 await,loginRes 是 Promise 对象
const user = await fetchUser(loginRes.token); // ❌ 运行时报错:Cannot read property 'token' of undefined
return user;
}
并发请求用 Promise.all + await,别傻等
如果几个请求彼此独立(比如同时拉取用户资料、通知数、未读消息),用 Promise.all 并发发,再 await 等全部完成,比一个接一个快得多:
async function loadDashboardData() {
try {
const [user, notifications, messages] = await Promise.all([
fetchUser(userId),
fetchNotifications(),
fetchMessages()
]);
return { user, notifications, messages };
} catch (err) {
// 注意:Promise.all 任一失败就 reject,需统一处理
console.error('某项数据加载失败', err);
throw err;
}
}
如果想“部分失败也不中断”,可用 Promise.allSettled:
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
const results = await Promise.allSettled([ fetchUser(), fetchNotifications(), fetchMessages() ]); const successful = results.filter(r => r.status === 'fulfilled').map(r => r.value);
避免 async/await 的典型坑
不要在循环里盲目 await——除非真要串行执行。比如批量提交表单,若每个都 await submit(item),就是纯串行,慢;想并发,就先收集 Promise,再 await Promise.all(...)。
不要给普通函数加 async 却不 await 任何东西——这只会无谓地把返回值包装成 Promise,增加理解成本。
await 只能用在 async 函数内——不能直接在顶层或普通回调里写 await fetch(...)(ES2022 支持顶层 await,但仅限模块作用域,且需环境支持)。
try/catch 要包住 await 表达式本身——而不是只包外层函数调用。否则错误会漏掉:
// ❌ 错误:fn() 抛错才捕获,但 await 内部出错不会进这个 catch
try {
fn(); // fn 内部有 await 但没 try/catch,错误会变成 unhandled rejection
} catch (e) { ... }
// ✅ 正确:await 前后都该在 try/catch 里,或确保内部已处理
async function fn() {
try {
const res = await fetch('/api');
return await res.json();
} catch (e) {
console.error(e);
throw e;
}
}
配合实际业务做分层与复用
复杂业务往往涉及状态管理、重试、缓存、节流。不要把所有逻辑堆在一个 async 函数里:
- 封装带重试的请求函数:
async function safeFetch(url, options = {}) { ... } - 用闭包或 class 管理 token 刷新逻辑,
await refreshTokenIfNeeded()自动插入到关键请求前 - 对高频操作(如搜索建议)加防抖,debounce 后再触发
await search(query) - 用
AbortController主动取消 pending 请求,避免组件卸载后更新已销毁的 state
async/await 不是银弹,但它让异步流程的意图更明确。重点是:理清数据依赖关系,选对串行还是并发,兜住错误,再逐步叠加健壮性策略。

















