Ajax重试机制怎么设置自适应延迟和避免重复提交?

俊蓓 Dev 阅读 21

在开发订单提交功能时,遇到网络波动导致Ajax请求失败需要重试。现在用递归setTimeout实现重试,但问题来了:retryCount++后每次固定延迟2秒,遇到服务器503错误时想改成指数递增延迟却搞不定。

更麻烦的是用户可能多次点击提交按钮,导致多个重试任务同时执行。试过用标志位isRequesting控制,但页面刷新后状态又会重置。有没有更好的方案同时解决动态延迟和防重提交?


let retryCount = 0;
function submitOrder() {
  return fetch('/api/order')
    .catch(err => {
      if (retryCount < 3) {
        setTimeout(() => submitOrder(), 2000);
        retryCount++;
      }
    });
}
我来解答 赞 3 收藏
二维码
手机扫码查看
2 条解答
UX泽睿
UX泽睿 Lv1
懒人方案:用个闭包存状态,指数退避加防重提交一起搞定。

let submitting = false;
function submitOrder() {
if (submitting) return Promise.reject('already submitting');
submitting = true;

const maxRetries = 3;
let retryCount = 0;

const attempt = () => fetch('/api/order')
.then(res => {
if (res.status === 503 && retryCount < maxRetries) throw new Error('503');
return res;
})
.catch(err => {
if (retryCount >= maxRetries) throw err;
retryCount++;
const delay = Math.pow(2, retryCount) * 1000; // 指数延迟 2^1*1s, 2^2*1s...
return new Promise(resolve => setTimeout(resolve, delay)).then(attempt);
});

return attempt().finally(() => { submitting = false; });
}
点赞 2
2026-02-13 06:00
百里兴瑞
省事的话,用个 pending 状态锁住按钮,再把延迟改成 2 的指数次方就行。

let isPending = false;
const maxRetries = 3;

async function submitOrder(event) {
if (isPending) return;
isPending = true;

for (let i = 0; i <= maxRetries; i++) {
try {
const res = await fetch('/api/order', { method: 'POST' });
if (res.ok || !res.headers.get('Retry-After')) return res;
} catch (err) {
if (i === maxRetries) throw err;
}
await new Promise(r => setTimeout(r, 2000 * Math.pow(2, i)));
}
}


按钮点击时传 event 进来,直接调 submitOrder(e),提交完记得 isPending = false,或者用按钮 disabled 控制也行。
点赞 6
2026-02-09 01:01