取消请求的必要性

在切换页面后,取消之前还未完成的axios请求,以免之前的请求结果影响当前页面的判断。

原理

实现的原理:

1、取消axios请求的方法;
2、将当前页面的请求取消方法存在state中,在router.beforeEach()钩子函数中遍历执行该取消方法。

取消axios请求的方法

其实原理都是通过axios的cancelToken属性来实现,在封装好的axios中添加以下代码:

const instance = axios.create({
  // baseURL: '',
  timeout: 30000 // 请求超时时间
});
let cancel = null
instance.interceptors.request.use(config => {
	config.cancelToken = new axios.CancelToken(cancel => {
    	cancel = cancel
  	})
})
// 当需要取消请求时,用cancel()来取消请求
instance.interceptors.response.use(err => {
  if (axios.isCancel(err)) {
    console.log('Request canceled', err.message);
    return
  } 
  // 处理错误
  console.error(err)
  return Promise.reject(err) // 返回接口返回的错误信息
})

结合vue路由跳转实现取消请求

接下来就是利用vuex和router来实现我们的需求

首先改造一下上面的代码,其实就是在axios.cancelToken函数返回中将所有请求添加到state中去:

// http.js
const instance = axios.create({
  // baseURL: '',
  timeout: 30000 // 请求超时时间
});
let cancel = null
instance.interceptors.request.use(config => {
	config.cancelToken = new axios.CancelToken(cancel => {
    	store.commit('addCancelToken', cancel)
  	})
})
 
// state/index.js
state: {
    platform: '',
    includeRouters: [],
    cancelTokenArr: []
},
mutations: {
	addCancelToken(state, cancel) {
      if (!state.cancelTokenArr) {
        state.cancelTokenArr = []
      }
      if (cancel) {
        state.cancelTokenArr.push(cancel)
      }
    },
    // 取消所有请求
    clearCancelToken(state) {
      state.cancelTokenArr.forEach(c => {
        if (c) {
          c()
        }
      })
      state.cancelTokenArr = []
    }
}

然后再router文件中增加router.beforeEach钩子函数:

router.beforeEach((to, from, next) => {
  // 切换路由时先取消所有请求
  store.commit('clearCancelToken')
})

OK,这样操作之后,切换路由时就会取消之前所有尚未返回结果的请求。

注意❗

注意: 在前端页面取消的请求并不会影响到后端,也就是说你已经发出去的请求后端还是会接收到,只不过前端不再接收服务器返回的结果了。

测试

我们来测试一下,这里介绍一个浏览器的设置,可以把浏览器的网速调慢,网速慢了请求响应就慢了,方便我们测试。

image.png

这里有一些默认的配置,也可以自定义网速,这里就不多介绍了,我们把网速切换为Fast 3G来测试一下。

image.png

当我快速切换两个路由时,上一个页面未完成的请求的状态为取消(canceled),证明我们成功啦。

扩展阅读