如何应对 async await 中的并发请求异常

作者:袖梨 2026-07-16
处理 async/await 并发异常需容错:用 Promise.allSettled 获取全量状态,封装 safeFetch 校验响应体,控制并发数并支持 AbortSignal 取消,按错误类型实施重试或降级。

处理 async/await 中的并发请求异常,关键不是“全成功才继续”或“一错就中断”,而是让系统具备容错能力——能区分失败类型、保留部分结果、可控重试、不泄露未卸载组件的副作用。

用 Promise.allSettled 替代 Promise.all

Promise.all 一拒即停,丢弃所有 pending 请求的结果;而 allSettled 总会返回每个请求的完整状态(fulfilled 或 rejected),便于逐个分析。

  • 它返回一个对象数组,每个对象含 status("fulfilled" / "rejected")、value(成功值)或 reason(错误原因)
  • 适合需要“尽力而为”的场景,比如批量提交表单、并行拉取用户资料、聚合监控指标
  • 示例:
    const results = await Promise.allSettled([fetch('/user/1'), fetch('/user/2')]);<br>results.forEach((r, i) => {<br>  if (r.status === 'fulfilled') console.log(`第${i+1}个成功`, r.value);<br>  else console.warn(`第${i+1}个失败`, r.reason);<br>});

对每个 fetch 做响应体校验

HTTP 状态码非 2xx 不等于 Promise 拒绝,fetch 默认只在网络层出错时 reject,401、500、404 都会 resolve —— 这容易导致后续 .json() 报错或空数据引发崩溃。

  • 在 await fetch() 后立即检查 res.ok,手动 throw 错误,确保业务逻辑能统一捕获
  • 可封装成通用函数:async function safeFetch(url) { const res = await fetch(url); if (!res.ok) throw new Error(`${res.status} ${res.statusText}`); return res; }
  • 这样配合 allSettled,就能把网络错误、服务端错误、权限错误都纳入 reason 字段,方便分类统计

控制并发数量 + 支持取消

100 个请求直接丢进 allSettled,可能压垮后端或触发 CDN 限流;用户切换页面时还在跑的请求,也可能造成 setState 报错。

  • 用 Promise.mapLimit(如 p-map 库)或手写分批执行,例如每次最多并发 6 个
  • 为每个 fetch 传入 AbortSignal,监听组件卸载(React 中用 useEffect cleanup、Vue 用 onBeforeUnmount)
  • 示例:
    const controller = new AbortController();<br>await fetch(url, { signal: controller.signal });<br>// 卸载时调用 controller.abort()

按需重试与降级策略

不是所有失败都要重试:DNS 失败重试无意义,超时可退避重试,404 就该直接放弃。

  • 对 transient 错误(如 NetworkError、503、timeout)做指数退避,最多试 2–3 次
  • 给关键请求设 fallback:比如头像加载失败显示默认图标,配置项获取失败用 localStorage 缓存值
  • 避免在 allSettled 回调里嵌套 await 重试——这会破坏并发性;应在发起前就决定是否重试,或用 retry-axios 等成熟封装

相关文章

精彩推荐