JS网络请求超时处理关键在于主动控制生命周期:需结合AbortController中断请求、Promise.race设定超时边界、自定义错误类分类抛出,并封装支持重试与退避的request函数。

JS 中网络请求超时的错误处理,关键不是“等它失败”,而是主动控制请求生命周期——用 Promise 封装时,要同时做到可中断、可识别、可复用。直接在 fetch 外套一层 setTimeout 并不可靠,因为请求本身还在后台运行;真正健壮的做法是结合 AbortController 与 Promise.race,再统一抛出语义明确的错误类型。
用 AbortController 中断请求并捕获超时错误
现代浏览器中,fetch 支持 signal 选项,这是实现“真超时”的基础。AbortController 能在超时后立即终止网络请求,避免资源浪费和状态错乱。
- 创建
AbortController实例,并传入signal到 fetch 配置中 - 用
setTimeout在指定毫秒后调用controller.abort() - 捕获
DOMException中的name === 'AbortError',即可确认是超时导致的中断 - 不要只依赖
catch捕获所有错误——需区分 AbortError、网络断开、DNS 失败等不同原因
用 Promise.race 包裹竞速逻辑,明确超时边界
Promise.race 是把“请求”和“倒计时拒绝”放在一起比快慢:谁先结束,就以谁的结果为准。这能确保业务层拿到的 Promise 必然会在规定时间内 settle。
- 封装一个
timeout(promise, ms)工具函数,内部返回Promise.race([promise, timeoutPromise]) -
timeoutPromise应为new Promise((_, reject) => setTimeout(() => reject(new ApiTimeoutError(ms, url)), ms)) - 注意:这个 race 只控制 Promise 状态,不中止 fetch;所以必须和 AbortController 配合使用,否则请求仍在后台发着
- 推荐将超时错误定义为自定义类(如
ApiTimeoutError),方便后续用instanceof精准判断
统一错误分类与抛出,解耦业务逻辑
一次请求失败可能有多种原因:断网、服务端 500、JSON 解析失败、超时、甚至响应 status 不在 2xx 范围。把这些都混在同一个 catch 里处理,后期维护成本极高。
- 提前定义错误子类:如
DisconnectError、ApiServerError、ApiTimeoutError、ApiJsonError - 在请求链中分阶段 throw:网络连通性检查 → fetch 执行 → status 校验 → JSON 解析 → 业务 code 判断
- 每个环节 throw 对应错误类型,让上层能按需处理,比如超时重试、断网提示、服务异常降级
- 错误实例中携带上下文(如
url、time、statusCode),便于日志追踪和监控告警
封装成可配置的 request 函数,支持重试与退避
超时处理不应孤立存在,而要嵌入完整的请求生命周期管理中。一个实用的封装,至少应支持超时、重试次数、指数退避、幂等判断。
- 函数参数包含
url、options(含 method、headers、body)、timeoutMs、retry、backoff - 重试逻辑放在 catch 内部:若错误是超时或网络类,且重试次数未用尽,则递归调用自身,延迟后发起下一次
- 退避策略建议用指数增长(如 100ms → 200ms → 400ms),避免雪崩式重试冲击服务端
- 对非幂等请求(如 POST),重试前应加确认或标记,防止重复提交


















