可利用闭包捕获的 AbortSignal 实现自动联动重试:共享同一 signal,任一请求中止则全部终止;重试前须检查 signal.aborted 或调用 signal.throwIfAborted();封装为高阶函数 withRetry,支持外部统一控制中止。

可以利用闭包捕获的 AbortSignal 实现带“自动联动重试”的异步函数:核心是让重试逻辑共享同一个 signal,一旦任意一次请求被中止(如超时、手动 abort),后续重试立即终止;同时在重试前检查 signal 是否已中止,避免无效发起。
共享同一 AbortSignal 实现联动中止
闭包可自然捕获外层创建的 AbortController 实例,确保所有重试调用共用其 signal。这样,只要调用 controller.abort(),当前进行中的请求和尚未发起的重试都会响应中止。
- 不要每次重试都新建
AbortController,否则各次请求互不感知 - 把
signal显式传给底层 fetch 或其他支持 signal 的异步操作 - 在重试前用
signal.aborted快速判断是否还需继续
重试逻辑需主动响应中止状态
即使 signal 已中止,若重试定时器(如 setTimeout)仍在排队,仍可能触发下一次调用。因此每次重试前必须检查:
if (signal.aborted) throw new DOMException('Aborted', 'AbortError')- 或直接 return,由上层统一处理中止异常
- 推荐用
signal.throwIfAborted()(现代浏览器支持),语义更清晰
封装成可复用的 retryable 函数
将重试策略与 signal 联动逻辑抽离,形成高阶函数:
<font color="#666">const withRetry = (fn, { maxRetries = 3, delay = 1000 } = {}) => {
return async function (...args) {
const controller = new AbortController();
const signal = controller.signal;
<pre class="brush:php;toolbar:false;">let lastError;
for (let i = 0; i setTimeout(r, delay * Math.pow(2, i)));
}
}
throw lastError;
}; };
使用时保持 signal 外露,便于外部控制:
const fetchWithRetry = withRetry(fetchWithSignal);<br>
const ctrl = new AbortController();<br>
fetchWithRetry(url, { signal: ctrl.signal })
联动重试的真实效果示例
比如发起一个 3 次重试的请求,2 秒后用户取消:
- 第 1 次请求发出,500ms 后失败 → 触发第 2 次(1s 后)
- 此时用户调用
ctrl.abort()→ signal.aborted 变为 true - 第 2 次请求正在 fetch 中,会收到
AbortError - 第 3 次重试尚未开始,进入循环时检查
signal.aborted,直接抛错退出
整个链路被干净切断,无残留定时器、无冗余网络请求。










