核心是用闭包封装重试策略与原始请求函数,捕获maxRetries、baseDelay、shouldRetry等参数,分层判断错误类型,结合指数退避+抖动+上限延迟,并支持多级策略组合。

核心是用闭包把重试策略(次数、退避公式、错误判断)和原始请求函数“绑在一起”,形成一个可复用、可配置、不污染业务逻辑的控制函数。
闭包结构要捕获关键参数
闭包外层接收原始异步函数和重试配置,内层返回一个新函数——它每次调用都复用这些配置,而不是每次重新传参。
-
必须捕获:最大重试次数(
maxRetries)、基础延迟(baseDelay)、错误过滤函数(shouldRetry) -
推荐捕获:是否启用抖动(
jitter),用于避免大量请求在同一时刻重试扎堆 - 原始函数(如
fetch封装或 Axios 请求方法)作为闭包变量被记住,不暴露给调用方
重试逻辑必须分层判断错误类型
不是所有失败都该重试。闭包内部的 try/catch 要做两层识别:
- 先看是不是网络类异常:比如
TypeError: failed to fetch、AbortError(注意:超时中断通常不重试)、502/503/504响应状态 - 再排除客户端错误:
400、401、403、404一般不重试;429(限流)可考虑带Retry-After头重试 - 把判断逻辑抽成独立函数传入,比如
shouldRetry: (err) => err.status >= 500 || err.name === 'TypeError',便于测试和替换
指数退避要带随机抖动与上限
延迟不能只是 baseDelay * 2^attempt,否则多个请求会在同一毫秒重试,可能触发对方限流。
- 计算延迟时加入 ±10%~30% 随机偏移(jitter),例如:
delay = Math.floor(baseDelay * Math.pow(2, attempt) * (0.7 + Math.random() * 0.6)) - 设置最大延迟上限(如 10 秒),防止第 10 次重试等 5 分钟——那已不是重试,是放弃前的挣扎
- 用
setTimeout+Promise实现非阻塞等待,别用await new Promise(r => setTimeout(r, delay))写死,而是封装成可取消的延迟工具
支持多级策略需嵌套闭包或组合函数
“多级”不是指重试 5 次,而是不同阶段用不同策略:比如前 2 次快速重试(200ms、400ms),后 3 次降频重试(1s、2s、4s),甚至失败后转备用接口。
- 可设计为策略数组:
strategies = [{ max: 2, base: 200 }, { max: 3, base: 1000 }],逐级 fallback - 更简洁的做法是让闭包接受一个“策略生成器”函数,根据当前尝试次数返回本次延迟和是否继续:
getStrategy: (attempt) => ({ delay: ..., shouldContinue: ... }) - 这样业务侧可自由组合:本地缓存兜底 → 主服务重试 → 备用服务降级 → 抛错

















