真正优雅的指数退避需具备自适应(间隔递增)、防冲突(含随机抖动)、有节制(设次数/时长上限、按错误类型区分、支持中止、协同超时控制)三特征。

识别 fetch 失败重试中是否真正实现了“优雅”的指数退避算法,关键不在于有没有重试,而在于重试行为是否具备**自适应、防冲突、有节制**三个特征。下面从可观察现象和代码结构两方面帮你快速判断。
看重试间隔是否随失败次数拉长
真正的指数退避,每次等待时间不是固定值(比如始终等1秒),而是明显递增:第1次失败后等约100ms,第2次约200–300ms,第3次约400–800ms,第4次可能已达1.5秒以上。如果日志或调试器里看到的重试延迟呈现“翻倍式增长”,基本符合指数规律;若全是相同间隔,只是加了 for 循环重试,那只是朴素重试,不是指数退避。
查是否有随机抖动(Jitter)逻辑
优雅实现一定会引入随机性。例如:等待时间不是精确等于 100 × 2ⁿ,而是落在 [100×2ⁿ/2, 100×2ⁿ] 或 [0, 100×2ⁿ] 的随机区间内。你可以在代码中搜关键词:random、jitter、Math.random()、prand;或者看是否调用了类似 setTimeout(fn, jitteredDelay) 这样的带变量延迟。没有抖动的指数退避,在多客户端场景下仍会形成“重试脉冲”,不算真正优雅。
确认是否设置了合理上限与退出条件
优雅实现不会无限等待或无脑重试。它通常包含以下约束:
- 最大重试次数(如 3~5 次),避免长期卡住
- 单次最大等待时长(如 ≤ 10 秒),防止用户长时间无响应
- 对错误类型做区分:400 类错误(参数错、权限不足)一般不重试;503/timeout/Network Error 才触发退避
- 重试前检查信号是否已中止(
signal?.aborted),及时放弃
观察是否与超时控制协同工作
单独的重试不解决请求挂起问题。优雅实现必然包裹在超时机制内——每个 fetch 请求自身带 AbortSignal 或封装了 timeout 逻辑。否则,一次卡死的请求会阻塞整个重试流程。你可以检查是否使用了 AbortController、是否在 fetch(..., { signal }) 中传入信号、是否用 Promise.race([fetch(), timeout()]) 做兜底。

















