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):
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:
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(...)。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
不要给普通函数加 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 不是银弹,但它让异步流程的意图更明确。重点是:理清数据依赖关系,选对串行还是并发,兜住错误,再逐步叠加健壮性策略。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










