前端接口失败重试怎么做才不卡死页面?
我在 Vue 项目里加了个接口失败自动重试的逻辑,但有时候网络差,连续重试好几次,页面就卡住了,用户操作都没反应。是不是我的重试方式有问题?
我试过用 setTimeout 延迟重试,也加了最大重试次数限制,但还是偶尔卡顿。比如下面这段代码:
<script setup>
import { ref } from 'vue'
import axios from 'axios'
const retryRequest = async (url, retries = 3) => {
try {
return await axios.get(url)
} catch (error) {
if (retries > 0) {
await new Promise(r => setTimeout(r, 1000))
return retryRequest(url, retries - 1)
}
throw error
}
}
</script>
这种写法在快速失败时会不会阻塞主线程?有没有更轻量、不卡 UI 的重试方案?
快速失败时最常见的问题是:请求立即失败然后立即重试,短时间内发了一堆请求,浏览器资源被吃满了。固定 1 秒延迟在网络抖动时也不够科学。
给你一个优化后的写法:
几个关键点:
第一,用 for 循环代替递归,更清晰也好控制。指数退避很重要,网络差的时候别急着连续重试,等久一点。
第二,axios 记得配 timeout。快速失败往往是请求发出去但一直 pending,加个 5 秒左右超时能让它早点进入 catch 触发重试逻辑。
第三,如果你在 Vue 里用,建议把请求挂到组件生命周期上,用 abortController 取消重复请求:
这样用户疯狂点击或者快速切换页面时,不会堆一堆请求。
还有个偏门但管用的招:如果你的重试逻辑特别重,可以把整个请求包装成 Promise 丢到 setTimeout(0) 里,下一帧再执行,给 UI 一个喘气的机会。不过正常情况下上面那些优化就够了。
注意安全的是,别在重试里带敏感参数重复发,有些接口重复调用会出问题。还有如果涉及支付类操作,建议别自动重试,让用户手动确认。