动态重试包装器需解耦重试与业务逻辑,支持调用时灵活配置maxRetries、baseDelayMs、retryOn和shouldCancel等参数,通过高阶函数封装异步执行器,实现指数退避、错误分类、AbortSignal兼容及运行时策略覆盖。

要编写支持动态重试策略的异步包装器,核心是把“重试逻辑”与“业务逻辑”解耦,同时允许在调用时灵活指定重试参数(如最大重试次数、退避策略、失败判定条件等),而不是写死在函数内部。
定义可配置的重试选项
先设计一个轻量级配置对象,承载重试所需的关键参数。例如:
- maxRetries:整数,最大尝试次数(含首次),默认 3
- baseDelayMs:基础延迟毫秒数,用于指数退避,默认 100
- retryOn:错误判断函数,接收 Error 实例,返回布尔值决定是否重试(例如只重试网络错误或特定状态码)
- shouldCancel:可选取消信号函数,返回 true 时中止重试(可用于配合 AbortSignal)
封装通用异步重试执行器
实现一个高阶函数,接收原始异步函数和重试配置,返回一个带重试能力的新函数:
- 使用递归或循环 + await 控制重试流程,每次失败后按策略等待再重试
- 首次调用直接执行;失败后检查 retryOn,不满足则立刻抛出原错误
- 延迟使用
new Promise(r => setTimeout(r, delay)),延迟时间可按指数增长(如baseDelayMs * 2 ** attempt)或固定/随机抖动 - 捕获并透传原错误堆栈,避免丢失上下文(可用
error.cause = originalError或自定义 error wrapper)
支持运行时策略覆盖与组合
让包装器能接受调用时传入的策略,优先级高于默认配置:
- 导出的包装函数本身可带默认策略,但允许调用方通过 options 参数覆盖部分字段
- 例如:
apiCall(...args, { maxRetries: 5, retryOn: err => err.status === 429 }) - 可进一步支持策略组合:比如将“网络超时重试”和“429 重试”两个策略 merge 成一个复合 retryOn 函数
适配主流异步场景(Promise / async-await / AbortSignal)
确保包装器兼容常见异步模式:
- 原函数返回 Promise,包装器也返回 Promise,并保持 resolve/reject 类型一致
- 支持传入 AbortSignal,在重试前检查
signal.aborted,已中止则立即 reject - 若原函数支持 signal(如 fetch),可将 signal 透传给它,同时在重试循环中监听中止
- 避免在重试中重复创建新 Promise 链导致难以调试,推荐用 async/await 显式控制流程
不复杂但容易忽略细节:错误分类、延迟精度、取消传播、类型推导(TypeScript 下注意泛型透传)。做好这几点,就能写出真正灵活、可测、可维护的动态重试包装器。

















