async/await 编写异步业务逻辑的核心是职责清晰、错误明确、按需并发、避免竞态;每个业务动作应封装为独立 async 函数,入口处用 try/catch 统一处理错误,非依赖操作用 Promise.all 并发,杜绝无脑串行 await 和遗漏 await。

用 async/await 编写干净的异步业务逻辑,核心是让代码看起来像同步一样可读,同时正确处理错误、避免竞态、合理组织流程,而不是简单地把 .then() 换成 await。
用 async 函数封装业务单元
每个明确的业务动作(如“提交订单”“获取用户配置”)都应是一个独立的 async 函数。它只做一件事,职责清晰,便于复用和测试。
例如:
async function fetchUserProfile(userId) {
const res = await fetch(`/api/users/${userId}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return res.json();
}
async function placeOrder(orderData) {
const res = await fetch('/api/orders', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify(orderData)
});
if (!res.ok) throw new Error('下单失败');
return res.json();
}
这样调用时逻辑一目了然:
立即学习“Java免费学习笔记(深入)”;
async function handleCheckout() {
try {
const user = await fetchUserProfile(123);
const result = await placeOrder({ userId: user.id, items: [...] });
showSuccess(result.orderId);
} catch (err) {
showError(err.message);
}
}
顺序执行 ≠ 硬性串行:按需并发
多个不依赖彼此的异步操作,不要傻等——用 Promise.all() 并发发起,再 await 整体结果,节省总耗时。
- ✅ 推荐:加载用户信息 + 用户偏好 + 未读消息(三者无依赖)
- ❌ 避免:先等用户信息,再等偏好,再等消息(纯串行,慢三倍)
写法示例:
async function loadDashboard() {
try {
const [user, prefs, notifications] = await Promise.all([
fetchUserProfile(123),
fetchUserPreferences(123),
fetchNotifications(123)
]);
renderDashboard({ user, prefs, notifications });
} catch (err) {
// 注意:Promise.all 中任一失败即 reject,需统一捕获
handleError(err);
}
}
正确处理错误:别让 await 吞掉异常
await 本身不会“吞”错误,但若没配 try/catch,错误会向上冒泡变成未处理的 promise rejection,可能静默失败或触发全局错误监听器。
关键原则:
- 在业务入口函数(如事件处理器、API 路由 handler)中加 try/catch,集中处理 UI 反馈或日志上报
- 在内部 async 工具函数里,该 throw 就 throw,让错误自然冒泡,不要随意 try/catch 后返回 null 或空对象(这会让调用方难以区分“没数据”和“出错了”)
- 需要降级逻辑时,明确 catch 并返回备选值,比如 fallback 图片 URL、缓存数据
示例:
async function loadAvatar(userId) {
try {
const res = await fetch(`/api/avatars/${userId}`);
if (res.ok) return res.url;
} catch (e) {
// 网络失败或 CORS 等,降级为默认头像
console.warn('头像加载失败,使用默认图', e);
}
return '/images/default-avatar.png';
}
避免常见陷阱
-
不要在循环中无脑 await:for 循环里 await 是串行;想并发请用
map().map(async () => ...)+Promise.all() -
不要忘记 await 调用 async 函数:写了
fetchUserProfile(123)却没加 await,得到的是 Promise 对象而非数据 - 避免“async 套 async”污染顶层:事件监听器、setTimeout 回调本身不是 async,需要用 IIFE 或显式 .then() 包裹;React useEffect 等生命周期中直接写 async 函数是语法错误
- 竞态问题要主动防御:比如搜索框防抖后多次输入,确保只处理最后一次请求的响应(可用 AbortController 或简单 flag 控制)


















