要实现支持动态重试的异步请求管理器,核心是解耦重试策略与请求逻辑,允许运行时调整次数、间隔、条件和退避方式;策略需封装为不可变对象,含maxretries、basedelayms、backofffactor、jitter和shouldretry函数;主函数接收url、选项、策略,用递归或循环+promise链执行,每次重试生成新abortcontroller并注入signal;提供cancelall、setglobalretrypolicy及overridepolicy等运行时控制接口;各请求保持独立重试上下文,避免状态共享。

要实现支持动态重试的异步请求管理器,核心在于把重试策略与请求逻辑解耦,同时允许运行时调整重试次数、间隔、条件和退避方式,而不是写死在代码里。
定义可配置的重试策略
策略应包含最大重试次数、初始延迟、退避倍数(如指数退避)、是否启用 jitter、以及决定是否重试的判定函数(例如只对 5xx 或超时重试,跳过 4xx)。用一个对象或类封装这些字段,便于传入和更新。
- 用普通 JS 对象即可,比如 { maxRetries: 3, baseDelayMs: 100, backoffFactor: 2, jitter: true, shouldRetry: (err, res) => res?.status >= 500 || err instanceof TimeoutError }
- 避免硬编码策略;让每次调用可传入不同策略,或通过 setter 动态修改默认策略
- 策略对象本身应是不可变的(每次修改返回新对象),防止多请求间意外共享状态
封装带重试逻辑的异步请求函数
主函数接收 URL、选项、策略三要素,内部用递归或循环 + Promise 链执行请求,并在失败时按策略判断是否重试。关键点是每次重试前计算当前延迟,并注入 AbortSignal 防止重复请求堆积。
用于 inference.sh 的 JavaScript/TypeScript SDK,可运行 AI 应用、构建代理、集成 150+ 模型。包名:@inferencesh/sdk(npm install),完整 TypeScript 支持。
- 用 setTimeout + Promise 控制延迟,而非 await new Promise(...)
- 每次重试生成新的 AbortController,并传递 signal 到 fetch,确保上一次请求能被真正中止
- 捕获网络错误、超时、响应状态异常等,统一交由 shouldRetry 判断,不盲目重试所有错误
暴露运行时控制接口
管理器实例需提供方法,让外部能在请求发起后干预重试行为,比如取消全部待重试任务、临时禁用重试、或为某次请求单独覆盖策略。
- 维护一个 WeakMap 关联请求 promise 与其控制器,支持 cancelByTag 或 cancelAll
- 提供 setGlobalRetryPolicy() 和 request(..., { overridePolicy: ... }) 双层控制能力
- 可选:发出事件(如 'retry-attempt', 'request-failed'),方便监控或调试
处理并发与上下文隔离
多个请求共用同一管理器时,必须保证彼此重试逻辑独立——不能因为一个请求重试影响另一个的计时器或状态。
- 每个请求生成独立的重试上下文(含当前尝试次数、已用延迟、随机 jitter 值)
- 避免使用闭包变量或 this.state 存储跨请求状态;推荐将上下文作为参数逐层传递
- 如果支持 AbortSignal 外部传入,需将其与内部重试信号合并(AbortSignal.any([external, internal]))
不复杂但容易忽略细节:重试不是越多越好,关键是让失败原因真正有机会恢复;动态性体现在策略可换、行为可控、上下文不串扰。










