axios取消重复请求CancelToken
可以让同一个请求遭到用户多次触发时,只返回最近的一次请求结果,而取消之前的请求。
在业务生产过程中,这个优化可以增强用户体验,减少不必要的数据接收和页面渲染。
使用它很简单,我们只要对axios进行一层封装:
// 封装axios请求
import axios from 'axios'
import config from '@/config'
import errorHandle from './errorHandle'
const CancelToken = axios.CancelToken
class HttpRequest {
constructor(baseURL) {
this.baseURL = baseURL
this.pending = {}
}
// 获取预设的配置
getInsideConfig() {
return {
baseURL: this.baseURL,
headers: { 'Content-Type': 'application/json;charset=utf-8' },
timeout: 10000,
withCredentials: false // 跨域时是否使用凭证,默认false
}
}
// 取请求url、method、params、data等组成key,标识这次请求
getPendingKey(config) {
return [
config.url,
config.method,
JSON.stringify(config.params),
JSON.stringify(config.data)
].join('&')
}
// 移除请求pending
removePending(key, isRequest = false) {
if (this.pending[key] && isRequest) {
this.pending[key]('取消重复请求')
}
delete this.pending[key]
}
// 拦截处理
interceptors(instance) {
// 添加请求拦截器
instance.interceptors.request.use(
config => {
// 1、取请求标识key
// 2、移除上一次该请求标识(如果有,则调用cancelToken取消上次请求)
// 3、给这次请求增加cancelToken备用(如果后续有重复请求则调用)
const key = this.getPendingKey(config)
this.removePending(key, true)
config.cancelToken = new CancelToken(cancel => {
this.pending[key] = cancel
})
return config
},
error => {
// 对请求错误做些什么
errorHandle(error)
return Promise.reject(error)
}
)
// 添加响应拦截器
instance.interceptors.response.use(
response => {
// 请求返回结果,移除pending
const key = this.getPendingKey(response.config)
this.removePending(key)
if (response.status === 200) {
return Promise.resolve(response.data)
} else {
return Promise.reject(response)
}
},
error => {
// 对响应错误做些什么
errorHandle(error)
return Promise.reject(error)
}
)
}
// 发送请求
request(config) {
const instance = axios.create()
const newOptions = Object.assign(this.getInsideConfig(), config)
this.interceptors(instance)
return instance(newOptions)
}
// 语法糖,get请求
get(url, config) {
const options = Object.assign(
{
url,
method: 'get'
},
config
)
return this.request(options)
}
// 语法糖,post请求
post(url, data, config) {
const options = Object.assign(
{
url,
data,
method: 'post'
},
config
)
return this.request(options)
}
// 语法糖,put请求
put(url, data, config) {
const options = Object.assign(
{
url,
data,
method: 'put'
},
config
)
return this.request(options)
}
// 语法糖,delete请求
delete(url, config) {
const options = Object.assign(
{
url,
method: 'delete'
},
config
)
return this.request(options)
}
}
HttpRequest.prototype.all = axios.all
HttpRequest.prototype.spread = axios.spread
export default new HttpRequest(config.baseURL)
这样在我们短时间内多次触发同一个请求时,在网络较慢,前一个请求还在pendding状态下,axios就可以取消掉前一次的请求。
但是该做法会潜藏一个问题,就是这些被取消的请求,还是会发给后端。这个问题导致的后果就是,比如我点击按钮插入数据,连续点击5次,虽然重复的被取消了,但是在后端依然接受到这5次请求,并执行了5次插入数据。
我在后端接口中埋了打印点,当被请求时触发:
所以以前刚开始理解的axios通过CancelToken取消重复请求,会把之前的取消掉,请求不会发出去给后端,这是错误的理解。
只要点击了按钮触发事件,请求就发出去了,尽管可以取消重复请求,只要网络还在连接,后端还是会一一收到所有的请求,该查库的查库,该创建的创建,只是重复请求返回的数据被前端取消了而已,前端只接受最后一次数据,渲染一次页面。
针对该问题,可以有多种优化方式,比如后端可以做控制,对于重复创建等操作进行限制,而在前端可以在按钮点击后显示loading状态等,以限制用户重复点击触发。
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!