← 返回题目列表

前端请求超时如何实现?Fetch 为什么没有内置 timeout?

高频 中等 第 3 / 26 题 更新于 2026/08/06
前端网络请求超时FetchAbortController

简化版

Fetch 没有直接的 timeout 配置,通常用 AbortControllersetTimeout 实现超时取消。超时不是简单报错,还要区分连接慢、服务端慢、用户取消、业务错误和网络断开。工程上要设置合理超时时间、清理 timer、避免重复提示、对幂等请求可重试,对非幂等请求谨慎处理。

详细版

基础封装如下:

async function fetchWithTimeout(url: string, options: RequestInit = {}, timeout = 10000) {
  const controller = new AbortController()
  const timer = setTimeout(() => controller.abort('timeout'), timeout)
  try {
    return await fetch(url, { ...options, signal: controller.signal })
  } finally {
    clearTimeout(timer)
  }
}
说明
AbortController取消 fetch
setTimeout到点触发 abort
finally清理定时器
错误分类区分超时和其他异常

超时策略是用户体验和系统保护,不是让后端业务自动回滚的魔法。

完整版教学

记忆钩子:前端请求超时如何实现?Fetch 为什么没有内置 timeout? 不只考 API 名称,更考“浏览器机制 + 工程边界 + 可观测指标”能不能串起来。

一、为什么需要请求超时

网络请求可能因为弱网、服务端卡住、网关排队、连接异常而长时间不返回。如果没有超时,页面 loading 会一直转,用户不知道发生了什么。

超时可以让前端及时给出反馈,也能释放一些客户端资源。

这一节放到前端工程里,至少要补上一个因果链:这个选择影响什么浏览器行为,用户在慢网、重复操作或页面切换时会看到什么结果,线上又该通过什么指标发现问题。比如同样是 100 次操作,正常路径可能 95 次都成功,但剩下 5 次边界路径如果没有取消、超时、降级或清理逻辑,就会变成请求竞态、内存泄漏、白屏或安全漏洞。把这层讲清楚,小节才不是口号,而是能指导实现的判断。

二、Fetch 为什么没有 timeout 字段

Fetch 的设计更倾向于用 AbortController 统一处理取消,包括用户取消、路由切换、组件卸载和超时。

也就是说 timeout 是一种取消原因,不是独立的网络能力。

这个小节要补足可验证的场景:在 前端请求超时如何实现?Fetch 为什么没有内置 timeout? 里,判断不能只停留在一句经验,而要说明触发条件、用户可见影响和工程兜底。可以把它拆成 3 步:先描述浏览器或框架实际发生了什么,再说明慢网、重复点击、页面切换或 SSR/CSR 差异会怎样放大问题,最后给出监控、降级、回滚或测试用例。这样一来,这个小节就能承担教学作用,而不是只作为结尾口号。

三、基础实现细节

实现时必须清理 timer。否则请求已经成功返回,定时器还在,后续触发 abort 会造成奇怪副作用或资源浪费。

try {
  const res = await fetch(url, { signal })
  return res
} finally {
  clearTimeout(timer)
}

finally 是最稳妥的清理位置。

四、错误分类

请求失败不等于超时。

类型示例处理
超时超过 10s提示重试或降级
用户取消切页、关闭弹窗通常静默
HTTP 错误500、404看业务提示
网络断开offline、DNS提示网络异常

错误分类可以改善用户提示和监控质量。

五、超时时间怎么定

不同接口不应一刀切。

  • 首屏关键查询:较短超时,失败给降级。
  • 大文件上传:更长超时,配合进度和断点续传。
  • 后台导出:可能改成异步任务轮询。
  • 写操作:超时后要查询结果,不能简单重复提交。

六、和重试的关系

超时后是否重试取决于请求是否幂等。GET 查询通常可以重试;POST 创建订单、支付确认等要谨慎,最好有幂等键。

if (isTimeout(error) && method === 'GET') {
  // 可以考虑重试
}

七、常见误区与追问

  • 误区:超时就是请求没有到服务端。 请求可能已经到达并被处理,只是响应没回来。
  • 误区:超时后可以无脑重试 POST。 写请求可能造成重复操作,必须有幂等设计。
  • 误区:Promise.race 超时就够了。 只 race 不 abort,底层请求可能还在继续。
  • 追问:为什么要 clearTimeout? 避免请求结束后定时器仍触发,造成资源浪费和误取消。
  • 追问:如何区分用户取消和超时? 可以记录 abort reason 或封装不同错误类型。
  • 追问:上传接口超时怎么设置? 上传耗时受文件大小和网络影响,应更长,并配合进度和断点续传。

八、加强记忆

请求超时记成“定时器触发 AbortController”。成功失败都清 timer;GET 可重试,POST 要幂等;超时只说明前端等不到,不代表后端没执行。