如果服务器返回比较慢的时候,用户又频繁切换路由,就会导致很多请求在等待响应,就容易导致浏览器卡死。
如果我们在每次路由跳转时取消了这些请求,就能很好的规避这种情况。
我们请求使用axios来完成,axios为我们提供了取消请求的方法,具体如何获取请阅读官方文档或者下文,下文仅展示了一种获取方式。
第一步
首先思考我们要在路由跳转时去取消请求,那在路由跳转前我们是不是得先把这些请求存起来,所以我创建了一个pinia(vuex同理)
// /store/myRequest.js
import { defineStore } from 'pinia'
export default defineStore('myRequest', {
state: () => ({
// 取消请求token数组
cancelTokens: []
}),
actions: {
// 添加
pushToken(token) {
this.cancelTokens.push(token)
},
// 取消并清空请求
cancelRequest() {
if (this.cancelTokens.length === 0) return;
this.cancelTokens.forEach(item => {
item()
})
this.cancelTokens = []
}
}
})
第二步
然后我们在请求拦截器中去获取并存储请求的取消方法
// /request/http.js
import axios from 'axios'
import useMyRequest from '../store/myRequest'
const CancelToken = axios.CancelToken;
// 路由跳转不清除请求白名单,如果有那种全局定时刷新的请求,不需要清除的,可以其接口放在这里
const cancelWhite = ['/user/news/xxx']
const myRequestStore = useMyRequest()
// 创建axios实例
const service = axios.create({
// ...省略
})
// 请求拦截器
service.interceptors.request.use(
config => {
// 存请求-用于路由跳转时清空请求,可以配置白名单
if (!cancelWhite.includes(config.url)) {
config.cancelToken = new CancelToken((c) => {
myRequestStore.pushToken(c)// 这里的c就是取消请求的方法
})
}
return config
},
error => {
return Promise.reject(error)
}
)
最后一步
好,上面的新增和存储都写好了,我们要在哪里去调用取消请求呢?
我们上面说了要在路由跳转时清除请求,那当然是在路由拦截器中去调用了。
// /router/index.js
// 省略路由配置代码等...
import useMyRequest from '@/store/myRequest'
// 拦截器
router.beforeEach((to, from, next) => {
// 取消请求
const myRequestStore = useMyRequest()
myRequestStore.cancelRequest()
})
其他
我们来测试一下,这里介绍一个浏览器的设置,可以把浏览器的网速调慢,网速慢了请求响应就慢了,方便我们测试。
这里有一些默认的配置,也可以自定义网速,这里就不多介绍了,我们把网速切换为Fast 3G来测试一下
当我快速切换两个路由时,上一个页面未完成的请求的状态为取消(canceled),证明我们成功啦。
补充
从 v0.22.0
开始,Axios 支持以 fetch API 方式—— AbortController
取消请求:
const controller = new AbortController();
axios.get('/foo/bar', {
signal: controller.signal
}).then(function(response) { //... });
// 取消请求
controller.abort()
所以我们上述的例子中,也可以改造为AbortController
这种方式来实现。CancelToken
这种方式会在Axiosv0.22.0
版本后被弃用。