
本文介绍如何通过合理使用 async/await 替代 .then() 链式调用,提升异步代码可读性与可维护性,并给出符合最佳实践的封装模式。
在现代 JavaScript 开发中,async/await 已成为处理异步逻辑的首选方式——它让异步代码看起来像同步代码,显著降低嵌套和回调带来的认知负担。相比传统的 .then().catch() 链式写法,await 能自然地将“等待结果”语义显式表达出来,使数据流一目了然。
你当前的写法存在两个典型问题:
- apiCall() 声明为 async 却在外部仍用 .then() 消费,未充分发挥 await 优势;
- 后续 fetchData() 中 console.log(fetchData()) 实际输出的是一个 Promise 对象(因为 fetchData 是 async 函数),而非预期的数据,这会导致调试困惑。
✅ 正确且更清晰的重构方式如下:
// 封装底层请求:明确返回业务数据(data),隐藏 axios 响应结构
const apiCall = async () => {
const { data } = await axios.get("https://api.example.com/data");
return data; // 直接返回解构后的 data,调用方无需再 .data
};
// 业务层逻辑:专注数据消费,代码线性、易读
const fetchData = async () => {
try {
const result = await apiCall(); // 等待数据就绪
console.log(result); // 直接拿到业务数据
return result;
} catch (error) {
console.error("API 请求失败:", error.message);
throw error; // 可选择重新抛出,便于上层统一错误处理
}
};
// 正确调用方式(必须在 async 上下文中)
(async () => {
try {
const data = await fetchData();
// ✅ 此处 data 即为实际响应体,非 Promise
} catch (err) {
// 处理 fetchData 抛出的错误
}
})();? 关键要点总结:
- 避免混合风格:不要在一个 async 函数内部用 .then(),也不要在顶层直接 console.log(asyncFn());始终用 await 消费 async 函数返回值;
- 分层职责清晰:apiCall 负责网络请求与响应标准化(如解构 data),fetchData 负责业务逻辑编排;
- 务必处理异常:await 后的 Promise 拒绝会抛出错误,需用 try/catch 包裹,否则会引发未捕获异常;
- 若需在非 async 环境(如事件处理器)中调用,可保留 .then(),但建议整个调用链统一风格,优先采用 async/await。
遵循以上模式,你的异步代码将更健壮、更易测试、也更容易被团队成员理解。










