export default {
name: “A”,
data() {
return {
source: null
};
},
methods: {
search() {
if(this.source){
// 如果上一次请求未完成,this.source不为null,则执行取消上一次请求的操作
this.cancel();
}
// CancelToken.source 工厂方法
let CancelToken = this.$axios.CancelToken;
this.source = CancelToken.source();
let url = “https://lianghj.top:8888/api/private/v1/rights/list”;
this.$axios.get(url, {
// 传入cancelToken,使该请求可取消
cancelToken: this.source.token,
}).then((res) => {
// 请求响应完成,this.source为null,不影响下次相同的请求
this.source = null;
})
},
cancel(){
// 取消请求
this.source.cancel(“取消重复请求!”);
}
},
};

此时,如果我们连续多次点击按钮,结果如下

axios如何暂停发送请求 axios取消请求的原理_前端

在上一次请求未响应完成,发起重复请求,则将上一次请求取消,以达到优化效果。

2、CancelToken 构造函数

我们也可以通过传递一个 executor 函数到 CancelToken 的构造函数来创建 cancel token

let CancelToken = axios.CancelToken;
let cancel;
axios.get(‘/user/12345’, {
cancelToken: new CancelToken(function executor© {
// executor 函数接收一个 cancel 函数作为参数
cancel = c;
})
});
// 取消请求
cancel();

实例

如下方式也能达到取消重复请求的效果



<el-button type=“plain” @click=“search”>搜索

我们知道,发出去的请求(处于pending阶段)可以使用以上两种方式进行取消或中断。那么,在真实的项目中,我们可能需要为全部的请求进行此项优化(取消重复请求),那又该如何去实现?

全局请求优化


这里会涉及到一个问题,我们为全局的请求进行此项优化时,如何判断是否为重复的请求呢?如我在发送1请求,紧接着去发送2请求,此时不算是重复请求,不需要取消;而当发送1请求,1请求还未响应完成时紧接着再去发送1请求,此时判定为重复请求,则执行取消上一次重复请求的操作。

1、如何判断重复请求?

当请求方式、请求 URL 和请求参数都一样时,我们就可以认为请求是一样的。因此在每次发起请求时,我们就可以根据当前请求的请求方式、请求 URL 地址和请求参数来生成一个唯一的 key,同时为每个请求创建一个专属的 CancelToken,然后把 key 和 cancel 函数以键值对的形式保存到 Map 对象中,使用 Map 的好处是可以快速的判断是否有重复的请求

let pendingRequest = new Map();
// 生成唯一的key
let requestKey = [method, url, JSON.stringify(params), JSON.stringify(data)].join(‘&’);
let cancelToken = new CancelToken(function executor(cancel) {
if(!pendingRequest.has(requestKey)){
// 如果发送的请求不存在,则进行保存
pendingRequest.set(requestKey, cancel); // 保存cancel函数,以便后续执行取消请求操作
}
})

当出现重复请求的时候,我们就可以使用 cancel 函数来取消前面已经发出的请求,在取消请求之后,我们还需要把取消的请求从 pendingRequest 中移除。

2、如何取消重复请求?

因为我们需要为全局请求进行此优化,此时可以在拦截器上添加相关配置。

在配置请求拦截器和响应拦截器前,我们先定义3个功能辅助函数。

getRequestKey:用于根据当前请求的信息,生成唯一的请求 key:

// 函数返回唯一的请求key
function getRequestKey(config) {
let { method, url, params, data } = config;
return [method, url, JSON.stringify(params), JSON.stringify(data)].join(“&”);
}
addPendingRequest:用于把当前请求信息添加到pendingRequest对象中:
let pendingRequest = new Map();
function addPendingRequest(config) {
let requestKey = getRequestKey(config);
config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {
if (!pendingRequest.has(requestKey)) {
pendingRequest.set(requestKey, cancel);
}
});
}

removePendingRequest:检查是否存在重复请求,若存在则取消已发的请求:

function removePendingRequest(config) {
let requestKey = getRequestKey(config);
if (pendingRequest.has(requestKey)) {
// 如果是重复的请求,则执行对应的cancel函数
let cancel = pendingRequest.get(requestKey);
cancel(requestKey);
// 将前一次重复的请求移除
pendingRequest.delete(requestKey);
}
}

3、配置拦截器

请求拦截器

axios.interceptors.request.use(
function (config) {
// 检查是否存在重复请求,若存在则取消已发的请求
removePendingRequest(config);
// 把当前请求信息添加到pendingRequest对象中
addPendingRequest(config);
return config;
},
function (error) => {
return Promise.reject(error);
}
);

响应拦截器

axios.interceptors.response.use(
function (response) => {
// 从pendingRequest对象中移除请求
removePendingRequest(response.config);
return response;
},
function (error) => {
// 从pendingRequest对象中移除请求
removePendingRequest(error.config || {});
if (axios.isCancel(error)) {
console.log(“已取消的重复请求:” + error.message);
} else {
// 添加异常处理
}
return Promise.reject(error);