一、axios异步并发 => 取消重复请求,只保留最后一次请求
1. AbortController (推荐)
从 v0.22.0 开始,Axios 支持以 fetch API 方式—— AbortController 取消请求
示例:封装接口请求index.js
1.1 在axios中声明数组记录标识
//axios异步并发1
let pending = [] //声明一个数组用于存储每个请求的标识
//AbortController取消请求1
let controller
let removePending = (config) => {
//查找数组中是否存在相同请求,存在则取消
if (pending && pending.length > 0) {
for (let p in pending) {
if (pending[p].u === config.url.split('?')[0] + '&' + config.method) {
if(pending[p].f){
pending[p].f() //执行取消操作
}
//axios AbortController取消请求2
controller.abort()
pending.splice(p, 1) //数组移除当前请求
}
}
}
}
1.2 在请求前校验拦截
class Request {
constructor(baseURL, timeout = 10000) {
this.instance = axios.create({
baseURL: 'https://juejin.cn/creator/content/column?status=all',
timeout,
headers: {
'Content-Type': 'application/json'
}
})
this.instance.interceptors.request.use(
(config) => {
//axios异步并发2
removePending(config) //在一个axios发送前执行校验取消操作
//axios AbortController取消请求3
pending.push({
u:
config.url.split('?')[0] +
'&' +
config.method
})
controller = new AbortController()
config.signal = controller.signal
config.controller = controller
return config
},
(err) => {
return err
}
)
}
}
1.3 在请求返回后维护声明数组pending
class Request {
constructor(baseURL, timeout = 10000) {
this.instance = axios.create({
baseURL: 'https://juejin.cn/creator/content/column?status=all',
timeout,
headers: {
'Content-Type': 'application/json'
}
})
this.instance.interceptors.response.use(
(res) => {
//axios异步并发3
// 清除当前记录
if (pending && pending.length > 0) {
for (let p in pending) {
if(pending[p].u === res.config.url.split('?')[0] + '&' + res.config.method) {
pending.splice(p, 1)
}
}
}
useLoadingData.showLoading = false
return res
},
(err) => {
//axios异步并发4
pending = [] //清空记录
// console.log("err", err)
useLoadingData.showLoading = false
// // return err
return Promise.reject(err)
}
)
}
}
完整示例:
const TIMEOUT = 10000
//axios异步并发1
let pending = [] //声明一个数组用于存储每个请求的标识
//AbortController取消请求1
let controller
let removePending = (config) => {
//查找数组中是否存在相同请求,存在则取消
if (pending && pending.length > 0) {
for (let p in pending) {
if (pending[p].u === config.url.split('?')[0] + '&' + config.method) {
if(pending[p].f){
pending[p].f() //执行取消操作
}
//axios AbortController取消请求2
controller.abort()
pending.splice(p, 1) //数组移除当前请求
}
}
}
}
class Request {
constructor(baseURL, timeout = 10000) {
this.instance = axios.create({
baseURL: 'https://juejin.cn/creator/content/column?status=all',
timeout,
headers: {
'Content-Type': 'application/json'
}
})
this.instance.interceptors.request.use(
(config) => {
//axios异步并发2
removePending(config) //在一个axios发送前执行校验取消操作
//axios AbortController取消请求3
pending.push({
u:
config.url.split('?')[0] +
'&' +
config.method
})
controller = new AbortController()
config.signal = controller.signal
config.controller = controller
return config
},
(err) => {
return err
}
)
this.instance.interceptors.response.use(
(res) => {
//axios异步并发3
// 清除当前记录
if (pending && pending.length > 0) {
for (let p in pending) {
if(pending[p].u === res.config.url.split('?')[0] + '&' + res.config.method) {
pending.splice(p, 1)
}
}
}
useLoadingData.showLoading = false
return res
},
(err) => {
//axios异步并发4
pending = [] //清空记录
// console.log("err", err)
useLoadingData.showLoading = false
// // return err
return Promise.reject(err)
}
)
}
request(config) {
if (config.sign) {
config.data = {
data: config.data || {}
}
}
return new Promise((resolve, reject) => {
this.instance
.request(config)
.then((res) => {
resolve(res.data || {})
})
.catch((err) => {
reject(err)
})
})
}
get(config) {
return this.request({ ...config, method: 'get' })
}
post(config) {
return this.request({ ...config, method: 'post' })
}
}
export default new Request(TIMEOUT)
2. CancelToken deprecated (不推荐)
您还可以使用 cancel token 取消一个请求。
Axios 的 cancel token API 是基于被撤销 cancelable promises proposal。
此 API 从
v0.22.0开始已被弃用,不应在新项目中使用。
2.1 在axios中声明数组记录标识
//axios异步并发1
let pending = [] //声明一个数组用于存储每个请求的标识
let cancelToken = axios.CancelToken
let removePending = (config) => {
//查找数组中是否存在相同请求,存在则取消
if (pending && pending.length > 0) {
for (let p in pending) {
if (pending[p].u === config.url.split('?')[0] + '&' + config.method) {
if(pending[p].f){
pending[p].f() //执行取消操作
}
pending.splice(p, 1) //数组移除当前请求
}
}
}
}
2.2 在请求前校验拦截
class Request {
constructor(baseURL, timeout = 10000) {
this.instance = axios.create({
baseURL: 'https://juejin.cn/creator/content/column?status=all',
timeout,
headers: {
'Content-Type': 'application/json'
}
})
this.instance.interceptors.request.use(
(config) => {
//axios异步并发2
removePending(config) //在一个axios发送前执行校验取消操作
config.cancelToken = new cancelToken((c) => {
// pending存放每一次请求的标识,config.url请求路径,config.method请求方法
pending.push({u: config.url.split('?')[0] + '&' + config.method, f: c});
})
return config
},
(err) => {
return err
}
)
}
}
2.3 在请求返回后维护声明数组pending
class Request {
constructor(baseURL, timeout = 10000) {
this.instance = axios.create({
baseURL: 'https://juejin.cn/creator/content/column?status=all',
timeout,
headers: {
'Content-Type': 'application/json'
}
})
this.instance.interceptors.response.use(
(res) => {
//axios异步并发3
// 清除当前记录
if (pending && pending.length > 0) {
for (let p in pending) {
if(pending[p].u === res.config.url.split('?')[0] + '&' + res.config.method) {
pending.splice(p, 1)
}
}
}
useLoadingData.showLoading = false
return res
},
(err) => {
//axios异步并发4
pending = [] //清空记录
// console.log("err", err)
useLoadingData.showLoading = false
// // return err
return Promise.reject(err)
}
)
}
}