简言:
项目中经常会出现重复的请求,比如:一个提交按钮被测试一秒内狂暴点击n+1次!bug单瞬间降临,而且可能一口气提出n个可优化点。(黑人问号.jpg)其结果就是产生了相同请求n次,后台就出现了n次提交记录,当然着非我们想要的。还有就是有些方法要监听页面的滚动拉伸来触发某些指定的请求,这也会造成请求被触发n次。所以就可以引出今天的主角cancel token
首先:我们看一下axios的介绍说明
Axios 的 cancel token API 基于cancelable promises proposal,它还处于第一阶段。
可以使用 CancelToken.source 工厂方法创建 cancel token,像这样:
const CancelToken = axios.CancelToken;
const source = CancelToken.source();
axios.get('/user/12345', {
cancelToken: source.token
}).catch(function(thrown) {
if (axios.isCancel(thrown)) {
console.log('Request canceled', thrown.message);
} else {
// 处理错误
}
});
axios.post('/user/12345', {
name: 'new name'
}, {
cancelToken: source.token
})
// 取消请求(message 参数是可选的)
source.cancel('Operation canceled by the user.');
还可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token:
const CancelToken = axios.CancelToken;
let cancel;
axios.get('/user/12345', {
cancelToken: new CancelToken(function executor(c) {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// cancel the request
cancel();
接下来我们就要对其进行简单封装或者改造应用于我们的项目中
1、我们要解决的问题就对于重复的,一致的请求我们要对其进行取消
2、在哪里做?由于所有请求都会经过拦截器,那么我们就在拦截器中做这个
既然这两个确定了那么已经算是完成一半了
import axios from 'axios'
const api = axios.create({
baseURL,
headers: {
'Content-Type': 'application/json;charset:UTF-8',
},
})
// 参数处理
const paramsLink = params => {
let urlStr = ''
if (params && typeof params === 'object') {
Object.keys(params).forEach(key => {
const val = params[key]
if (val || val == 0) {
// 对参数进行连接(其实可以随意连接满足对比目的即可)
urlStr += `#${key}=${val}`
}
})
}
return urlStr
}
// 存储所有的请求(为后续对比)
let pending = []
let cancelToken = axios.CancelToken
let cancelPending = config => {
let params = config.data ? config.data : config.params
if (
pending.length > 1 &&
pending[pending.length - 2].u === config.method + config.url + paramsLink(params)
) {
pending[pending.length - 2].f() //取消上一次请求
pending.splice(pending.length - 2, 1) //移除
}
}
// 请求拦截器
api.interceptors.request.use(
config => {
config.cancelToken = new cancelToken(c => {
let params = config.data ? config.data : config.params
// 这里的axios标识用请求方法+请求地址+请求参数拼接的字符串
pending.push({ u: config.method + config.url + paramsLink(params), f: c })
})
cancelPending(config)
return config
},
error => {
return Promise.reject(error)
},
)
// 回馈拦截器
api.interceptors.response.use(
response => {
// 200/正常响应情况
const resData = {
...response.data,
code: response.data.code || errorStatus,
}
return resData
},
error => {
// 对error进行处理
if (error == 'Cancel') return Promise.resolve(error)
// 接下来你可以做一些错误的处理
},
)
好啦,基本处理过程都有展现如有疑问可以留言探讨