持续创作,加速成长!这是我参与「掘金日新计划 · 10 月更文挑战」的第29天,点击查看活动详情
一:引言
小伙伴们在日常开发中肯定经常使用axios,在使用过程中大家有没有考虑到axios的两个请求场景?
取消重复请求
同一个接口数据重复请求了n次,我们只需要第一次请求,其它请求需要全部取消
取消上一次请求
在请求当前接口数据时,取消上一次接口的请求。使用场景如tab选项卡,假设点击每个选项卡都会发起一个接口请求,如果最新点击的tab接口数据快于上一次tab接口数据,那么最新的数据渲染就是上一个接口的数据了,此时我们在tab选项卡切换的时候要取消上一次的请求。
二:axios中取消请求api
网上关于axios取消请求的介绍太多了,但是大部分都是cancelToken的介绍,很不幸这个方法已经废弃了。但是网上还充斥着许多关于cancelToken的介绍,想到这心里顿时一万个草泥马。
正确取消axios请求的姿势
//1.创建取消请求对象
const controll = new AbortController()
//2.在axios参数内部添加signal属性
axios({
method:"get",
url:"xxx",
signal:controll.signal,
})
//3.在需要取消请求的地方直接调用
controll.abort()
根据上面三步走,狗都能取消axios请求了。哈哈哈
三:取消重复请求
取消重复请求,实际上我们可以配合按钮的禁用属性灵活的解决,当请求发出时,禁用按钮点击。当请求完成时再恢复按钮点击。今天我们重点是考虑如何基于axios拦截器取消重复请求。
设计思路
- 配置axios的请求拦截器和响应拦截器
- 设计一个根据请求参数生成唯一字符串的函数,此函数我们可以分析请求是否属于重复请求。
- 设计一个数组,保存所有请求生成的字符串
- 在请求拦截器处,根据当前请求参数生成字符串,然后判断字符串是否在数组存在。如果存在说明请求重复了,直接取消当前请求,反之正常请求并将字符串添加到数组
- 在响应拦截器处,在请求响应后,删除数组中对应请求保存的字符串。
axios封装请求
import axios from "axios";
const instance = axios.create({
baseURL:"/api",
timeout:5000
})
//任务队列
let que = []
//根据每次的请求生成hash字符串
function createHash(config) {
const {data,params,method,url} = config
if(data) data = JSON.stringify(data)
if(params) params = JSON.stringify(params)
return [method,url,data,params].join("*")
}
/**请求拦截 */
instance.interceptors.request.use(function (config) {
//1.请求前生成hash
let hash = createHash(config)
const {controll} = config
//2.如果hash存在,取消本次请求
if(que.includes(hash)) {
console.log("重复了")
controll.abort()
}
//3.否则,添加hash,正常执行
que.push(hash)
return config;
}, function (error) {
return Promise.reject(error);
});
/**响应拦截 */
instance.interceptors.response.use(function (response) {
//1.执行完成,从队列删除hash
const hash = createHash(response.config)
que.splice(que.indexOf(hash),1)
return response;
}, function (error) {
//2.执行完成,从队列删除hash(虽然错误,也要删除hash)
if(error.message!="canceled") {
const hash = createHash(error.config)
que.splice(que.indexOf(hash),1)
}
return Promise.reject(error);
});
export default instance
App.vue进行测试
<template>
<div>
<!--取消重复请求例子-->
<h2>测试取消重复请求案例</h2>
<div @click="getData()">点击请求数据</div>
</div>
</template>
<script setup>
import instance from './services/index';
/**模拟取消重复请求 */
const getData = async() => {
const controll = new AbortController()
try{
let info = await instance({
method:"get",
url:"/",
signal:controll.signal,
controll
})
console.log(info)
}catch(e){
console.log(e)
}
}
</script>
界面演示
我们连续点击3次,可以看见第一次请求后,之后的两次请求都被直接取消了。最后只输出最后一次的请求数据
四:取消上一次请求
上面已经提到了取消上一次请求的使用场景,我们看下面的例子
此处我们模拟一个tab选项卡,点击每一个选项卡都会发起一次数据请求,那么如何取消上一次请求? 由于取消上一次请求的设计可以通过一个控制变量实现。因此我们简单封装了axios
设计思路
取消上一次请求的设计,核心就是保存上一次取消请求的控制变量,我们可以直接使用一个变量保存上一次请求的取消控制器的变量,每次在请求新接口数据时,如果控制变量非空可以直接取消上一次请求。
index2.js
import axios from "axios";
const instance = axios.create({
baseURL:"/api",
timeout:5000
})
export default instance
App.vue
<template>
<div>
<h2>测试取消上一次请求案例</h2>
<div class="box">
<div class="title">
<div @click="getInfo(1)">请求接口1</div>
<div @click="getInfo(2)">请求接口2</div>
</div>
<div class="content">
{{show}}
</div>
</div>
</div>
</template>
<script setup>
import instance2 from './services/index2';
import {ref} from "vue"
/**模拟取消上一次请求 */
let pre = null//1.标记前一次的请求控制器
const show = ref()
const getInfo = async(data) => {
//2.每次请求都定义自己的控制器
const controll = new AbortController()
//3.如果上次的非空,取消上次请求
if(!pre) pre = controll
else {
console.log("取消")
pre.abort()
pre = controll
}
try{
let info = await instance2({
method:"get",
url:"/",
signal:controll.signal
})
if(data==1) show.value = 1
else show.value = 2
}catch(e){
console.log(e)
}
}
</script>
<style>
.box{
border:1px solid red;
width: 300px;
height: 300px;
}
.title{
display: flex;
justify-content: space-around;
}
</style>
界面展示
我们频繁的在接口1和接口2上点击,最后只请求了最后一次请求。
项目地址
项目小demo已经放在github上,需要的伙伴可以直接下载进行演示。