【前端续命术】请求总失败?给你的 AJAX 装上 “不死鸟” 重试 Buff

前言

精心写好的 AJAX 请求,本地测试百发百中,一到线上就间歇性 "摆烂"------ 网络抽风、服务器手抖、甚至只是宇宙射线干扰(bushi),请求就哐哐报错。

要是每次失败都直接抛给用户 "请求失败,请刷新页面" ,用户体验直接原地爆炸。这时候,给请求加个 "重试机制" 就显得尤为重要了 ------ 就像打游戏复活,失败了咱再来一次,让它失败了能自动重来。

一、先看痛点:不稳定的 AJAX 请求

先看这个模拟 AJAX 请求的代码,它模拟了网络请求的随机性:有 80% 的概率失败,20% 的概率成功,就像现实中那些不靠谱的接口一样:

JavaScript 复制代码
// 模拟不稳定的AJAX请求
function ajax() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            // 生成0-9的随机数
            const random = ~~(Math.random() * 10);
            if (random < 8) {
                console.log('请求失败😭');
                reject('fail');
            } else {
                console.log('请求成功🎉');
                resolve('success');
            }
        }, 1000)
    })
}

// 普通调用:失败了就凉了
ajax()
    .then(res => console.log(res))
    .catch(err => console.log(err))

直接调用这个ajax函数,大概率会看到 "请求失败" 的提示,要是这是用户支付的关键请求,不得把用户急哭?这时候,咱们的 "重试神器" 就该登场了。

二、打造重试函数:失败了咱再来!

核心思路很简单:写一个retry函数,接收 "要执行的请求函数""重试次数",每次请求失败后,就减少一次重试次数,只要次数没耗光,就重新发起请求;直到成功,或者次数用完彻底失败。

JavaScript 复制代码
// 模拟不稳定的AJAX请求
function ajax() {
    return new Promise((resolve, reject) => {
        setTimeout(() => {
            const random = ~~(Math.random() * 10);
            if (random < 8) {
                console.log('请求失败😭');
                reject('fail');
            } else {
                console.log('请求成功🎉');
                resolve('success');
            }
        }, 1000)
    })
}

// 重试核心函数:给请求加"复活甲"
function retry(fn, count) {
    // 返回一个新的Promise,统一对外暴露结果
    return new Promise((resolve, reject) => {
        // 封装请求执行逻辑,方便递归调用
        const run = () => {
            fn()
                .then((res) => {
                    // 请求成功:直接resolve结果,结束流程
                    resolve(res);
                    console.log(`终于成了!结果:${res}`);
                })
                .catch((err) => {
                    // 请求失败:先减少重试次数
                    count--;
                    console.log(`还剩${count}次重试机会`);
                    // 还有重试次数:递归调用run,再来一次
                    if (count) {
                        console.log('准备重试...');
                        run();
                    } else {
                        // 次数用完:彻底失败,reject结果
                        reject('重试次数耗尽,请求彻底失败💥');
                    }
                })
        }
        // 首次执行请求
        run();
    })
}

// 调用重试函数:最多重试 3次
retry(ajax, 3)
    .then(res => console.log(`最终结果:${res}`))
    .catch(err => console.log(`最终结果:${err}`));

就算前两次都失败,第三次成功了,整个流程就会返回成功;如果 3 次都失败,就会输出:

关键逻辑拆解:

  • 外层 Promiseretry函数返回新 Promise,不管内部重试多少次,对外只暴露最终的成功 / 失败结果,符合 Promise 的链式调用习惯
  • run 函数递归 :把请求逻辑封装在run里,失败后只要还有重试次数,就递归调用run,实现 "自动重试"
  • 次数控制 :每次失败count--,当count为 0 时,不再重试,直接reject,避免无限循环

三、进阶小技巧:让重试更 "聪明"

当然,实际开发中咱们的重试机制可以更完善,比如:

  • 添加延迟重试:失败后不要立刻重试,等几百毫秒再试(避免高频请求压垮服务器)
  • 指数退避:重试间隔越来越长(比如 1s→2s→4s),更符合网络请求的最佳实践
  • 自定义失败条件:不是所有失败都重试(比如 404 是资源不存在,重试也没用)

举个加延迟的小改造:

JavaScript 复制代码
function retry(fn, count, delay = 1000) {
    return new Promise((resolve, reject) => {
        const run = () => {
            fn()
                .then(res => {
                    resolve(res);
                    console.log(`终于成了!结果:${res}`);
                })
                .catch(err => {
                    count--;
                    console.log(`还剩${count}次重试机会`);
                    if (count) {
                        console.log(`等待${delay}ms后重试...`);
                        // 延迟重试
                        setTimeout(run, delay);
                    } else {
                        reject('重试次数耗尽,请求彻底失败💥');
                    }
                })
        }
        run();
    })
}

结语

写代码就像过日子,哪能事事一帆风顺? 修复 bug 也是人生中繁琐的乐趣。

相关推荐
空中海2 小时前
第四章:Vue Router
前端·javascript·vue.js
竹林8182 小时前
从零集成RainbowKit:我如何在一个周末搞定多链钱包连接并填平三个大坑
前端·javascript
2601_953465612 小时前
M3U8 在线播放器:无需安装,一键调试 HLS 直播流
开发语言·前端·javascript·开发工具·m3u8·m3u8在线播放
Ruihong2 小时前
你写的是 Vue,跑起来是纯 React?这是什么黑科技
vue.js·react.js·面试
qq_12084093712 小时前
Three.js 工程向:资源生命周期管理与显存回收实践
前端·javascript·orbitcontrols
MaoziShan2 小时前
CMU Subword Modeling | 23 Syllables and Syllabification
前端·人工智能·机器学习·语言模型·自然语言处理·中文分词
帅次2 小时前
Android 高级工程师面试参考答案:Framework、生命周期、View 与 Binder
android·面试·binder
2501_913061342 小时前
网络原理之HTTP(3)
java·网络·网络协议·http·面试
M ? A2 小时前
VuReact 1.6.2 发布,新一代 Vue 3 转 React 编译工具
前端·javascript·vue.js·react.js·面试·开源·vureact