debounce
函数,限制短期内无法重复调用接口 - 使用 lodash
的 debounce
函数实现disabled=true
实现),避免返回值覆盖
disabled
和loading
均设置为true
false
axios
的取消请求:axios取消请求0.21.1
,使用CancelToken
AbortControllerAbortController
:AbortController() 构造函数AbortController实现方法
const controller = new AbortController();
const {
data: { data },
} = await this.$http.get('/api/v1/xxx'
params,
signal: controller.signal
})
// 取消请求
controller.abort()
CancelToken实现方法
data() {
return {
...
cancelToken: null,
}
},
// 防抖
searchOptions: debounce(
async function (searchString) {
// 取消上一次的请求
if (this.cancelToken) {
this.cancelToken.cancel()
}
// 创建 cancelToken
this.cancelToken = axios.CancelToken.source()
this.loading = true
const params = {...}
const {
data: { data },
} = await this.$http.get('/api/v1/xxx'
params,
cancelToken: this.cancelToken.token, // 请求时传入token
})
// 数据处理...
this.loading = false
// 清除cancelToken
this.cancelToken = null
},
300,
{
leading: false,
trailing: true,
}
),
cacheAdapterEnhancer(axios.defaults.adapter, option)
option
对象,可选
enabledByDefault
:是否默认缓存,Boolean
类型, 默认是true
(缓存), false
(不缓存)cacheFlag
:是否通过flag
方式缓存,字符串类型, 只有flag
一样才会缓存,flag
不对或者没设置的都不会缓存。defaultCache
:可以配置maxAge
(缓存有效时间, 毫秒单位),默认是5分钟,max
(支持缓存的请求的最大个数),默认是100个import axios from 'axios'
import { Cache, cacheAdapterEnhancer } from 'axios-extensions'
const request = axios.create({
baseURL: process.env.BASE_URL,
adapter: cacheAdapterEnhancer(axios.defaults.adapter, {
defaultCache: new Cache({ maxAge: 2000, max: 100 }),
}),
})
throttleAdapterEnhancer(adapter, options)
option
对象,可选
threshold
:限制请求调用的毫秒数,数字类型, 默认是1000cache
:可以配置 max
(节流请求的最大个数),默认是100个retryAdapterEnhancer(adapter, options)
option
对象,可选
times
:重试的次数,Number
类型, 默认是2,请求失败后会重试2次。axios
的 HTTP 请求管理类:http.ts import axios, { AxiosRequestConfig, CancelTokenSource } from 'axios'
// 引入请求函数 包含一些请求拦截器或其他设置
import { request } from './axiosConfig'
// 枚举 指定响应数据的格式(这里只举例1种返回体格式)
enum ResponseType {
ResData, // 返回 res.data
}
// 完整的响应对象结构
interface ApiResponse<T> {
data: {
code: number
message: string
data: T | null | undefined
}
status: number
headers?: Record<string, string>
config?: any
request?: any
}
// 异步请求的结果
type HttpResult<T> = Promise<T | ApiResponse<T> | any>
// 扩展了 Axios 的请求配置,添加了两个自定义字段以支持请求取消功能
interface CustomAxiosRequestConfig extends AxiosRequestConfig {
cancelPrevious?: boolean // 是否取消之前的请求
cancelTokenId?: string // 保存取消请求tokenId
}
class Http {
// 存储 Http 类的实例,以便实现单例模式
private static instancesMap: Map<string, Http> = new Map()
// 存储与请求 URL 关联的取消令牌源,用于实现请求取消功能
private static cancelTokenIdSourceMap: Map<string, CancelTokenSource> =
new Map()
private requestFunction: (config: AxiosRequestConfig) => Promise<any> // 请求方法
private responseType: ResponseType = ResponseType.ResData // 相应数据格式类型
// 构造函数-接收参数以配置请求函数、响应类型和公共URL前缀,同时初始化相关属性
constructor({
requestMethod = request,
responseType = ResponseType.ResData,
}: {
requestMethod?: (config: AxiosRequestConfig) => Promise<any>
}) {
this.requestFunction = requestMethod
this.responseType = responseType
}
// 私有异步方法,用于执行 HTTP 请求,接受请求方法、URL 和配置
private async createRequest<T>({
method,
url,
config,
}: {
method: 'get' | 'post' | 'delete' | 'put'
url: string
config: CustomAxiosRequestConfig
}): HttpResult<T> {
let source, cancelTokenId
if (config?.cancelPrevious) {
// 取消之前的请求
cancelTokenId = config?.cancelTokenId ?? this.getCancelTokenId(url)
this.cancelPreviousRequest(cancelTokenId)
// 创建新的取消令牌
source = axios.CancelToken.source()
}
// 准备请求配置
const requestConfig: AxiosRequestConfig = {
...config,
method,
url,
cancelToken: source?.token,
}
// 请求
try {
// 保存取消令牌
if (cancelTokenId) Http.cancelTokenIdSourceMap.set(cancelTokenId, source)
// 发起请求
const res = await this.requestFunction(requestConfig)
// 没有遇到重复请求-清空取消令牌
if (cancelTokenId) Http.cancelTokenIdSourceMap.delete(cancelTokenId)
// 返回响应值
if (this.responseType === ResponseType.ResData) {
return res.data as T
} else {
return res as ApiResponse<T>
}
} catch (error) { // 错误处理
if (axios.isCancel(error)) {
console.error('Request canceled', error.message)
} else {
if (cancelTokenId) Http.cancelTokenIdSourceMap.delete(cancelTokenId)
console.error('Error:', error)
}
throw error
}
}
private cancelPreviousRequest(cancelTokenId: string): void {
const source = Http.cancelTokenIdSourceMap.get(cancelTokenId)
source?.cancel(`Cancelled request ${cancelTokenId}`)
}
private getCancelTokenId(url: string): string {
return url.split('?')[0] // 提取非 query 部分, 防止同一个get请求不同query时没取消
}
// 实现get方法
public get<T>(
url: string,
config?: CustomAxiosRequestConfig
): HttpResult<T> {
return this.createRequest<T>({ method: 'get', url, config })
}
// 实现post方法
public post<T>(
url: string,
data?: any,
config?: CustomAxiosRequestConfig
): HttpResult<T> {
return this.createRequest<T>({
method: 'post',
url,
config: { ...config, data },
})
}
// 实现delete方法
public delete<T>(
url: string,
config?: CustomAxiosRequestConfig
): HttpResult<T> {
return this.createRequest<T>({ method: 'delete', url, config })
}
// 实现put方法
public put<T>(
url: string,
data?: any,
config?: CustomAxiosRequestConfig
): HttpResult<T> {
return this.createRequest<T>({
method: 'put',
url,
config: { ...config, data },
})
}
// 单例
// 该方法检查是否已经存在相同 ID 的实例,如果不存在,则创建一个新的实例并存储在 instancesMap 中。
// 这样做的目的是减少同类实例的创建,确保在应用中使用的是同一个 Http 实例,从而管理配置和状态
public static getInstance({
requestMethod = request,
responseType = ResponseType.ResData,
instanceId = 'http',
}: {
requestMethod?: (config: AxiosRequestConfig) => Promise<any>
responseType?: ResponseType
instanceId?: string
}): Http {
let instance = Http.instancesMap.get(instanceId)
if (!instance) {
instance = new Http({ requestMethod, responseType })
Http.instancesMap.set(instanceId, instance)
}
return instance
}
}
// 导出实例
export const http = Http.getInstance({
requestMethod: request,
responseType: ResponseType.ResData,
instanceId: 'http',
})
// Axios 请求实例
const request = axios.create({
baseURL: process.env.BASE_URL,
adapter: cacheAdapterEnhancer(axios.defaults.adapter, {
defaultCache: new Cache({ maxAge: 2000, max: 100 }),
}),
})
await this.$http.post(
`/xxx/xxx/${this.id}/xxx`,
params
)
来学习下axios的扩展插件1
来学习下axios的扩展插件2