别再乱用 async/await 了!90% 前端都踩过的 5 个隐形坑

现在前端开发,只要写异步请求,基本人手一把 async/await。写法简洁、代码同步化、可读性高,几乎成了项目标配。

但很多同学只是"会用",并不懂底层执行机制,日常开发中经常出现:接口串行卡死、报错直接白屏、并发请求冗余、try/catch 滥用等隐性问题。

这些 bug 往往不是必现问题,属于"偶发玄学 bug",排查起来极其痛苦。

今天我总结日常工作中最容易踩、最容易被忽略的 5 个 async/await 实战深坑,全部都是业务真实踩坑,看完直接规避 90% 异步代码问题。


坑一:所有接口无脑串行,导致页面加载巨慢

很多新手写代码,习惯性一个 await 接一个 await:

javascript 复制代码
const getInfo = async () => {
  const user = await getUser()
  const list = await getList()
  const banner = await getBanner()
}

看起来没毛病,但是三个接口毫无依赖关系,却强行串行执行。

假设每个接口 300ms,串行总耗时接近 900ms,但其实完全可以并发执行。

正确写法:Promise.all 并发提速

scss 复制代码
const getInfo = async () => {
  const [user, list, banner] = await Promise.all([
    getUser(),
    getList(),
    getBanner()
  ])
}

总耗时直接缩短为最慢的那一个接口耗时,页面首屏速度大幅提升。

核心原则:无依赖接口一定并发,有依赖接口再串行。


坑二:Promise.all 一个报错,全部崩盘

Promise.all 有一个致命特性:只要一个请求报错,整体直接 reject,所有成功的数据全部拿不到。

业务场景中非常不合理:比如首页多个模块接口,一个模块挂了,不应该让整个首页白屏。

解决方案:使用 Promise.allSettled

scss 复制代码
const resList = await Promise.allSettled([
  getUser(),
  getList(),
  getBanner()
])

返回结果会区分 fulfilled 成功和 rejected 失败状态,我们可以自行过滤有效数据,容错性拉满。


坑三:忘记 await,出现"异步幽灵 bug"

这是工作中出现频率最高、最难排查的问题。

代码看似没问题,但变量永远是 Promise 对象,拿不到真实数据:

javascript 复制代码
const getData = async () => {
  return await request.get('/api/list')
}

// 错误用法
const list = getData() 
console.log(list) // Promise 对象

所有 async 函数返回一定是 Promise,无论内部有没有写 await。

上层调用必须加 await 或者 .then 取值,否则永远拿不到结果。

这种 bug 经常出现在:循环调用、事件回调、初始化函数中,极其隐蔽。


坑四:try/catch 乱包裹,报错范围过大

很多同学为了防止接口报错白屏,直接把所有逻辑全包进 try 里:

scss 复制代码
try {
  const user = await getUser()
  setUserName(user.name)
  const list = await getList()
} catch (err) {
  message.error('请求失败')
}

问题:

  • 用户接口报错 → 列表接口直接不执行
  • 代码逻辑卡死,无法局部降级
  • 报错信息模糊,不知道哪个接口挂了

最佳实践:单个接口单独捕获异常

关键接口单独 try/catch,互不影响,支持局部降级,体验更好。


坑五:forEach 中使用 await,完全不生效

无数前端踩过这个经典大坑:

javascript 复制代码
arr.forEach(async (item) => {
  await request(item)
})
console.log('执行完成') 
// 实际:不等异步结束就直接执行了

结论:forEach 不支持异步等待。

因为 forEach 内部不会等待 Promise 完成,会直接一次性全部执行完毕,导致异步逻辑错乱。

正确写法:使用 for 循环

css 复制代码
for (let i = 0; i < arr.length; i++) {
  await request(arr[i])
}

需要并发就配合Promise.all,稳定不出错。


总结

async/await 看着简单,实则非常讲究细节。很多线上卡顿、偶现 bug、数据错乱问题,根源都是以上几个不显眼的写法问题。

简单回顾最佳规范:

  • 无依赖接口用 all 并发,提升速度
  • 多模块请求用 allSettled 容错
  • async 函数调用必加 await
  • 精细 try/catch,不一把全包
  • 异步遍历拒绝 forEach,优先 for 循环

如果你全部规避掉,你的异步代码质量直接超过大部分业务前端。

相关推荐
易师傅1 小时前
技术面试已死?AI 时代,真正拉开程序员差距的是什么?
前端·后端·程序员
Hilaku6 小时前
你们公司有 35 岁以上的前端吗?
前端·javascript·程序员
AI前端工程狮6 小时前
服务端已经死了,客户端却报"超时"
人工智能·程序员
楠风测开7 小时前
两个任务同时跑,B 的登录态为什么被踢回登录页
程序员
codigger7 小时前
大厂git提交规范
git·程序员
挖掘狂人7 小时前
六条分支,一条主干:我的 Git 分支管理心得
git·后端·程序员
程序员cxuan8 小时前
再见了 Typora
人工智能·后端·程序员
深蓝AI11 小时前
45 万星的开源逆向 MCP:REA 让 Agent 无源码读懂任意应用,把证据和边界写进设计
人工智能·程序员
陈随易1 天前
Cmder 停更 17 个月,2.0 支持 Windows Terminal
前端·后端·程序员
kyriewen1 天前
我扫了 814 个依赖,97 个还敢要 Node 10
前端·javascript·程序员