VueJS与Axios:中止网络请求后组件加载状态不更新
问题根源
原方案失效的核心是被中止请求的finally回调会覆盖新请求的loading状态,具体执行顺序如下:
- 触发
fetchData后,首先同步执行CANCEL_PENDING_REQUESTS,中止所有待处理请求——这些请求的catch和finally会被加入微任务队列等待执行。 - 同步设置
loadingSpendingCard = true,此时loading为true。 - 发送新请求(同步操作)。
- 当前同步代码执行完毕,事件循环处理微任务队列,所有被中止请求的
finally回调依次执行,将loadingSpendingCard设为false——刚设置的true直接被覆盖,导致新请求的loading不生效。
对于20+请求的场景,批量中止会触发大量finally回调,批量重置loading状态,问题更突出。
解决方案
你尝试的“请求取消时不重置loading”是正确方向,可优化为适配多请求的通用方案:
- 在Axios请求拦截器中,给每个请求绑定
AbortController的同时,携带对应loading状态的标识(比如loadingKey),并将控制器和标识存入VueX。 - 在请求的
catch中,用axios.isCancel(error)判断是否是取消错误,仅处理非取消的异常。 - 在
finally中,仅当请求未被取消时,才将对应loading设为false。
示例调整代码:
// 请求拦截器配置 axiosApiClient.interceptors.request.use(config => { const controller = new AbortController(); config.signal = controller.signal; // 把控制器和loading标识存入VueX this.$store.commit('ADD_PENDING_REQUEST', { controller, loadingKey: config.loadingKey }); return config; }); // 组件内fetchData方法 methods: { fetchData() { this.$store.dispatch("CANCEL_PENDING_REQUESTS"); this.loadingSpendingCard = true; axiosApiClient.get("/user-spending", { loadingKey: 'loadingSpendingCard' // 传递当前请求对应的loading标识 }) .then(res => console.log(res)) .catch(err => { // 仅处理非取消的错误 if (!axios.isCancel(err)) console.error(err); }) .finally(() => { // 判断当前请求是否被取消,未取消才重置loading // 可通过VueX中记录的已取消请求列表,或在catch中标记状态 if (!this.currentRequestCancelled) { this.loadingSpendingCard = false; } }); } }
另外,也可以把所有loading状态统一托管到VueX:取消请求时不修改loading,新请求发起时直接将对应loading设为true,请求完成(非取消)时设为false,彻底避免多个请求的回调互相干扰。
内容的提问来源于stack exchange,提问作者Zayed
相关产品推荐
相关产品推荐

