Vue组件销毁时怎么正确取消Axios请求?请求还是在后台执行了

兴慧 Dev 阅读 56

在做商品列表页的时候,当快速切换路由时,之前的Ajax请求还在后台完成了,导致新页面的数据被旧数据覆盖。我试过在beforeDestroy里调用cancel函数,但控制台还是报错说响应拦截器被调用了。

我用了axios的CancelToken,代码大概是这样的:


this.source = axios.CancelToken.source();
axios.get('/api/products', {
  cancelToken: this.source.token
}).then(res => {
  this.products = res.data;
});

beforeDestroy() {
  this.source.cancel('组件销毁');
}

可是当我在路由切换时,虽然控制台能看到”取消错误”,但后端返回的数据还是触发了.then里的代码,把新页面的数据给覆盖了。难道cancel只是阻止了Promise状态更新?有没有更好的办法彻底终止请求?

另外页面有个加载动画的CSS:


.loading {
  opacity: 0;
  transition: opacity 0.3s;
  &.active {
    opacity: 1;
  }
}

这个动画在请求取消后还是会执行完过渡效果,感觉和请求状态不一致。

我来解答 赞 14 收藏
二维码
手机扫码查看
2 条解答
♫怡瑶
♫怡瑶 Lv1
你的问题出在取消请求的时机和响应拦截器的处理上。Axios 的 CancelToken 取消请求后,Promise 会进入 rejected 状态,但你没有正确捕获这个错误,导致代码继续执行。

解决办法是,在每个请求的 catch 中判断是否是主动取消的错误,并阻止后续逻辑。代码可以这么改:

this.source = axios.CancelToken.source();
axios.get('/api/products', {
cancelToken: this.source.token
}).then(res => {
if (this._isDestroyed) return; // 防止组件销毁后更新数据
this.products = res.data;
}).catch(err => {
if (!axios.isCancel(err)) throw err; // 只忽略取消错误
});

beforeDestroy() {
this.source.cancel('组件销毁');
}


至于加载动画的问题,可以在取消请求时同步移除动画状态。比如在 catch 里手动关闭动画标志位:

// 假设你用一个变量控制动画状态
data() {
return {
isLoading: false
};
}

// 请求开始时
this.isLoading = true;

axios.get('/api/products', {
cancelToken: this.source.token
}).then(res => {
if (this._isDestroyed) return;
this.products = res.data;
}).catch(err => {
if (!axios.isCancel(err)) throw err;
}).finally(() => {
this.isLoading = false; // 无论成功还是取消都关闭动画
});


差不多就这样,记得处理好 Promise 的 rejected 状态就行。
点赞 2
2026-02-19 16:01
Zz俊荣
Zz俊荣 Lv1
你这个问题是典型的 Axios 取消请求没处理好的情况。cancel 只是阻止了 Promise 的正常状态变化,但回调还是可能执行。建议在请求前先判断是否已经取消:

data() {
return {
source: null,
isCancelled: false
}
},
created() {
this.source = axios.CancelToken.source();
axios.get('/api/products', {
cancelToken: this.source.token
}).then(res => {
if (!this.isCancelled) { // 加个判断
this.products = res.data;
}
}).catch(err => {
if (axios.isCancel(err)) {
this.isCancelled = true;
} else {
console.error(err);
}
});
},
beforeDestroy() {
this.source.cancel('组件销毁');
}


至于加载动画的问题,可以在 beforeDestroy 里直接移除 .active 类或者重置样式,应该能用。
点赞 6
2026-01-31 18:22