工作中偶尔遇到切换tab请求数据的场景,然而当每个Tab下的数据量较大时接口返回较慢;此时测试也不按正常思维测试😂来回操作切换Tab导致页面显示的数据错误的问题。就这样喜提BUG单一个🤦♂️
解决
cancelToken是什么
CancelToken是Axios提供了一个实用的特性,它允许我们取消一个或多个正在进行的请求。
基础用法
在axios请求配置中添加CancelToken申明与其对应使用的isCancel 是判断是否为主动中断请求的状态值。可使用isCancel状态做其他逻辑操作。
axios
.get(url, {
cancelToken: new axios.CancelToken(function executor(c) {
cancel = c; // 将取消函数赋值给外部变量
}),
})
.catch((err) => {
if (axios.isCancel(err)) {
console.log('请求已取消!', err);
} else {
console.log('其他错误!', err);
}
});
全局封装使用
- 封装类
import axios from 'axios'
export default class CancelRequest {
constructor() {
this.pendingRequest = new Map()
// 控制重复请求的接口地址
this.controlUrl = ['/resource-catalog/video/channel/square/page/new', '/mission/approval/selectMissionChannelDraftByPage']
}
// 根据请求信息生成唯一标识key
geterateReqKey(config) {
const { url, method } = config
return this.controlUrl.includes(url) ? [url, method].join('&') : ''
}
// 把正在请求的接口信息添加到pendingRequest对象中
addPendingRequest(config) {
const requestKey = this.geterateReqKey(config)
config.cancelToken =
config.cancelToken ||
new axios.CancelToken((cancel) => {
if (!this.pendingRequest.has(requestKey) && requestKey != '') {
// 把请求取消方法作为 map 值存起来
this.pendingRequest.set(requestKey, cancel)
}
})
}
// 检查是否存在重复请求,若存在则取消前一次请求
removePendingRequest(config) {
const requestKey = this.geterateReqKey(config)
if (this.pendingRequest.has(requestKey)) {
const cancel = this.pendingRequest.get(requestKey)
// 取消请求
cancel(requestKey)
// 删除map中对应的属性
this.removeRequestKey(config)
}
}
// 从pendingRequest中删除对应的key
removeRequestKey(config) {
const requestKey = this.geterateReqKey(config)
this.pendingRequest.delete(requestKey)
}
}
- 使用时引入类
import RequestCanceller from './requestCanceller'
let requestCanceller = new RequestCanceller()
- 处理请求拦截
axiosInstance.interceptors.request.use(
function (config) {
// 在请求开始之前检查先前的请求,如果是重复请求,删除之前的
requestCanceller.removePendingRequest(config)
// 如果不存在 就将当前请求添加到pendingRequest
requestCanceller.addPendingRequest(config)
return config
},
function (error) {
return Promise.reject(error)
}
)
- 处理响应拦截
axiosInstance.interceptors.response.use(
(response) => {
// 移除成功请求记录
requestCanceller.removeRequestKey(response.config)
if (response.status === 200) {
if (response && response.data && response.data.code === 413) {
debounce(() => {
Message.warning({
message: '该用户无此权限',
showClose: false,
})
})
return
} else {
return response.data
}
}
return response
},
(error) => {
// 失败时也需要移除请求记录
requestCanceller.removeRequestKey(error.config || {})
}
)
缺点
- 性能开销:每次请求都需要创建和管理取消令牌,令牌管理会带来一定的内存开销。
- 用户体验:netWork会显示接口cancel状态,会让用户觉得是页面数据接口出错。