javascript请求重试需用有序队列保证顺序:串行执行、失败放回队首、isrunning锁防并发,支持优先级插队与abortcontroller取消。

在 JavaScript 请求重试中,若需保持请求顺序(比如依赖前序请求返回结果、日志时序、幂等性控制或服务端严格按序处理),不能简单对每个请求独立重试,而应将请求纳入一个**有序的重试队列**,确保:同一队列中,请求按入队顺序发起,失败后进入重试等待,但不打乱后续请求的位置。
用 Promise 链 + 队列状态管理维持顺序
核心思路是:不并发执行队列中的请求,而是串行驱动——每次只处理队列首项;若失败,则将其“放回队首”并延迟重试,其余请求原地等待;成功则出队,继续下一项。
- 维护一个数组队列(
queue: Array Promise<any>, resolve, reject, retryCount }></any>) - 定义一个
processQueue()函数,递归调用自身:取出队首,执行请求;成功则resolve并继续;失败且未达最大重试次数,则重置其重试计数并插回队首(不是队尾!),再延时后重试 - 所有
fetchWithRetry()调用都只是push到队列并返回一个新 Promise,由队列统一调度
避免“重试抢占”:禁止并发触发新请求
如果用户连续调用多次重试请求(如快速点击提交按钮),必须确保它们严格按调用顺序入队,且队列始终只有一个活跃执行者。常见错误是没加锁,导致多个 processQueue() 同时运行,破坏顺序。
- 用一个布尔标志
isRunning = false控制:仅当!isRunning时才启动处理循环 - 每次开始处理前设为
true,全部完成(包括空队列)后再设为false,并检查是否需立即启动下一轮 - 不使用
async/await在循环里直接for...of,因为 await 会释放控制权,可能被新入队打断;坚持用递归 +then/catch驱动
支持优先级与中断(可选进阶)
纯 FIFO 可能不够灵活。若需支持高优请求插队(如取消操作、心跳保活),可在入队时允许指定 priority 字段(如 0 普通,-1 最高),插入时按优先级排序而非简单 push;但要注意:插队不能破坏“已入队未完成请求”的相对顺序,即只允许插到“尚未开始执行”的请求之前。
- 入队时用
queue.sort((a, b) => a.priority - b.priority),但仅对priority !== undefined的项生效 - 已进入执行流程的请求不受影响;新请求只影响排队中的待处理项
- 若需取消某请求,给它绑定一个
AbortController,并在入队对象中保存abort方法,提供cancel(id)接口从队列中移除并 abort
实际代码片段示意(精简版)
以下为关键逻辑骨架,不含错误处理细节:
let queue = [];
let isRunning = false;
<p>function enqueue(reqFn, options = {}) {
const { maxRetries = 3, delay = 1000 } = options;
return new Promise((resolve, reject) => {
queue.push({ reqFn, resolve, reject, retryCount: 0, maxRetries, delay });
if (!isRunning) runQueue();
});
}</p><p>function runQueue() {
if (queue.length === 0) {
isRunning = false;
return;
}
isRunning = true;</p><p>const item = queue.shift();
item.reqFn()
.then(res => {
item.resolve(res);
runQueue(); // 继续下一个
})
.catch(err => {
if (item.retryCount </p>Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











