async/await 不是银弹:JavaScript 异步错误处理的三个实战规则

举报
yd_278701352 发表于 2026/10/28 10:07:06 2026/10/28
【摘要】 async/await 让异步代码看起来像同步代码,这既是它的优点,也是坑的来源。很多人以为写上 await 就万事大吉,结果线上报错悄悄被吞掉,或者几个请求明明可以并行却被写成了串行。下面三条规则,是我在实际项目里踩过坑后固定下来的做法。第一条规则:每个 await 都要有错误归属。await 后面的 Promise 一旦 reject,又没有 try/catch 接住,错误会沿着调用链一...

async/await 让异步代码看起来像同步代码,这既是它的优点,也是坑的来源。很多人以为写上 await 就万事大吉,结果线上报错悄悄被吞掉,或者几个请求明明可以并行却被写成了串行。下面三条规则,是我在实际项目里踩过坑后固定下来的做法。

第一条规则:每个 await 都要有错误归属。await 后面的 Promise 一旦 reject,又没有 try/catch 接住,错误会沿着调用链一直往上冒,直到变成 unhandledrejection——浏览器控制台里只剩一行警告,接口却静默失败了。正确姿势是:在真正能处理错误的那一层包 try/catch,而不是每一层都包。底层封装请求时只做必要的转换(比如把 HTTP 状态码转成统一的错误对象),不要在底层把错误 console.log 一下就吞掉;页面层或业务入口再统一 catch,做提示、重试或上报。还有一个常见死角:async 函数里 return 的值会被自动包成 Promise,所以在 async 函数里 throw 和 return Promise.reject 效果一样,别在同一函数里混用两种写法,增加排查难度。

第二条规则:能并行的别串行,但要分清 all 与 allSettled。初学者常写出这样的代码:await 请求 A,再 await 请求 B——A 和 B 互不依赖时,这就是在浪费时间。改成 const [a, b] = await Promise.all([getA(), getB()]),总耗时等于最慢的那个,而不是两者之和。但 Promise.all 有个硬脾气:其中一个失败,整个结果就失败,其他请求的结果也拿不到。如果业务上“部分成功也可以接受”(比如同时拉取用户信息和推荐列表,推荐挂了不应该挡住页面),就用 Promise.allSettled,再按 status 逐个处理 fulfilled 和 rejected。选哪个不看习惯,看业务能不能接受“一损俱损”。

第三条规则:超时、取消、重试要显式设计,不能靠“用户刷新页面”。真实网络不会永远守约:接口 hang 住时,没有超时的 await 会一直挂着,页面转圈到天荒地老。给关键请求加超时并不复杂,用 AbortController 就行:建一个 controller,setTimeout 到时调用 abort,fetch 收到信号后 reject,catch 里区分 AbortError 做“请求超时”的提示。重试也一样:不要在 catch 里无脑递归重试,至少加两条约束——最多重试次数(一般 2–3 次),以及退避间隔(第一次等 1 秒、第二次等 2 秒),避免服务端刚抖动一下就被重试洪峰打垮。把这三件套写进统一的请求封装里,每个业务调用自动受益,比每个页面各自手写可靠得多。

三条规则总结起来就一句话:错误要有归属、并行要看业务、超时重试要显式。async/await 写起来像同步代码,但它底下仍然是异步世界——用同步的写法偷懒,就会付出异步的代价。

【声明】本内容来自华为云开发者社区博主,不代表华为云及华为云开发者社区的观点和立场。转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息,否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0)

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。