import type { AxiosRequestConfig, Canceler } from 'axios'; import axios from 'axios'; import { isFunction } from '/@/utils/is'; // Used to store the identification and cancellation function of each request let pendingMap = new Map<string, Canceler>(); export const getPendingUrl = (config: AxiosRequestConfig) => [config.method, config.url].join('&'); export class AxiosCanceler { /** * Add request * @param {Object} config */ addPending(config: AxiosRequestConfig) { this.removePending(config); const url = getPendingUrl(config); config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => { if (!pendingMap.has(url)) { // If there is no current request in pending, add it pendingMap.set(url, cancel); } }); } /** * @description: Clear all pending */ removeAllPending() { pendingMap.forEach((cancel) => { cancel && isFunction(cancel) && cancel(); }); pendingMap.clear(); } /** * Removal request * @param {Object} config */ removePending(config: AxiosRequestConfig) { const url = getPendingUrl(config); if (pendingMap.has(url)) { // If there is a current request identifier in pending, // the current request needs to be cancelled and removed const cancel = pendingMap.get(url); cancel && cancel(url); pendingMap.delete(url); } } /** * @description: reset */ reset(): void { pendingMap = new Map<string, Canceler>(); } } 这是做什么的
时间: 2024-04-18 19:27:58 浏览: 174
这段代码是一个用于管理取消 Axios 请求的辅助工具类。它包含了以下功能:
1. `addPending(config: AxiosRequestConfig)`: 添加请求到待取消列表中。它会根据请求的方法和 URL 生成一个唯一的标识,并将该标识和取消函数存储在 `pendingMap` 中。
2. `removeAllPending()`: 清除所有待取消的请求。它会遍历 `pendingMap` 中的所有取消函数,并执行它们,然后清空 `pendingMap`。
3. `removePending(config: AxiosRequestConfig)`: 从待取消列表中移除指定的请求。它会根据请求的方法和 URL 生成标识,并从 `pendingMap` 中获取对应的取消函数,然后执行该函数并将其从 `pendingMap` 中删除。
4. `reset()`: 重置待取消列表。它会将 `pendingMap` 重置为空的 Map。
这个工具类的主要作用是在发送请求之前添加请求到待取消列表中,然后根据需要进行取消或清除请求。这在处理页面跳转或组件卸载时非常有用,可以避免因为未完成的请求导致的问题。
相关问题
import axios from 'axios' import type { CancelTokenStatic, AxiosRequestConfig, AxiosInstance, AxiosError, InternalAxiosRequestConfig, AxiosResponse, CancelTokenSource } from 'axios' import { useGlobalStore } from '@/stores' import { hasOwn, hasOwnDefault } from '@/utils' import { ElMessage } from 'element-plus' /** * @description: 请求配置 * @param {extendHeaders} {[key: string]: string} 扩展请求头用于不满足默认的 Content-Type、token 请求头的情况 * @param {ignoreLoading} boolean 是否忽略 loading 默认 false * @param {token} boolean 是否携带 token 默认 true * @param {ignoreCR} boolean 是否取消请求 默认 false * @param {ignoreCRMsg} string 取消请求的提示信息 默认 Request canceled * @param {contentType} $ContentType 重新定义 Content-Type 默认 json * @param {baseURL} $baseURL baseURL 默认 horizon * @param {timeout} number 超时时间 默认 10000 * @return {_AxiosRequestConfig} **/ interface _AxiosRequestConfig extends AxiosRequestConfig { extendHeaders?: { [key: string]: string } ignoreLoading?: boolean token?: boolean ignoreCR?: boolean ignoreCRMsg?: string } enum ContentType { html = 'text/html', text = 'text/plain', file = 'multipart/form-data', json = 'application/json', form = 'application/x-www-form-urlencoded', stream = 'application/octet-stream', } const Request: AxiosInstance = axios.create() const CancelToken: CancelTokenStatic = axios.CancelToken const source: CancelTokenSource = CancelToken.source() const globalStore = useGlobalStore() Request.interceptors.request.use( (config: InternalAxiosRequestConfig) => { globalStore.setGlobalState('loading', !hasOwnDefault(config, 'ignoreLoading', true)) config.baseURL = hasOwnDefault(config, 'baseURL', '/api') config.headers = { ...config.headers, ...{ 'Content-Type': ContentType[hasOwnDefault(config, 'Content-Type', 'json')], }, ...hasOwnDefault(config, 'extendHeaders', {}), } hasOwnDefault(config, 'token', true) && (config.headers.token = globalStore.token) config.data = config.data || {} config.params = config.params || {} config.timeout = hasOwnDefault(config, 'timeout', 10000) config.cancelToken = source.token config.withCredentials = true hasOwnDefault(config, 'ignoreCR', false) && source.cancel(hasOwnDefault(config, 'ignoreCRMsg', 'Request canceled')) return config }, (error: AxiosError) => { return Promise.reject(error) } ) Request.interceptors.response.use( (response: AxiosResponse) => { globalStore.setGlobalState('loading', false) const { data, status } = response let obj = { ...data } if (!hasOwn(data, 'status')) obj.status = status return obj }, (error: AxiosError) => { globalStore.setGlobalState('loading', false) ElMessage.error(error.message) return Promise.reject(error) } ) export default (config?: _AxiosRequestConfig) => Request(config) 修改代码,使其能够批量取消请求
可以通过创建一个 CancelToken 的数组来存储每个请求的 CancelToken,然后在需要取消请求的时候遍历这个数组并调用对应的 cancel 函数。具体的修改如下:
```
import axios, { AxiosInstance, AxiosRequestConfig, AxiosError, AxiosResponse, CancelTokenSource, Canceler } from 'axios'
import { useGlobalStore } from '@/stores'
import { hasOwn, hasOwnDefault } from '@/utils'
import { ElMessage } from 'element-plus'
interface _AxiosRequestConfig extends AxiosRequestConfig {
extendHeaders?: { [key: string]: string }
ignoreLoading?: boolean
token?: boolean
ignoreCR?: boolean
ignoreCRMsg?: string
contentType?: ContentType
baseURL?: string
timeout?: number
cancelToken?: CancelTokenSource['token'] | Canceler
}
enum ContentType {
html = 'text/html',
text = 'text/plain',
file = 'multipart/form-data',
json = 'application/json',
form = 'application/x-www-form-urlencoded',
stream = 'application/octet-stream',
}
const Request: AxiosInstance = axios.create()
const globalStore = useGlobalStore()
let cancelTokens: CancelTokenSource[] = []
Request.interceptors.request.use(
(config: _AxiosRequestConfig) => {
globalStore.setGlobalState('loading', !hasOwnDefault(config, 'ignoreLoading', true))
config.baseURL = hasOwnDefault(config, 'baseURL', '/api')
config.headers = {
...config.headers,
...{ 'Content-Type': ContentType[hasOwnDefault(config, 'contentType', 'json')] },
...hasOwnDefault(config, 'extendHeaders', {}),
}
if (hasOwnDefault(config, 'token', true)) {
config.headers.token = globalStore.token
}
config.data = config.data || {}
config.params = config.params || {}
config.timeout = hasOwnDefault(config, 'timeout', 10000)
const source = CancelToken.source()
config.cancelToken = source.token
cancelTokens.push(source)
if (hasOwnDefault(config, 'ignoreCR', false)) {
config.cancelToken = new CancelToken((cancel) => {
cancelTokens.push({ token: source.token, cancel })
})
source.cancel(hasOwnDefault(config, 'ignoreCRMsg', 'Request canceled'))
}
return config
},
(error: AxiosError) => {
return Promise.reject(error)
}
)
Request.interceptors.response.use(
(response: AxiosResponse) => {
globalStore.setGlobalState('loading', false)
const { data, status } = response
let obj = { ...data }
if (!hasOwn(data, 'status')) obj.status = status
return obj
},
(error: AxiosError) => {
globalStore.setGlobalState('loading', false)
ElMessage.error(error.message)
return Promise.reject(error)
}
)
export default (config?: _AxiosRequestConfig) => {
if (config && config.cancelToken) {
const tokens = Array.isArray(config.cancelToken) ? config.cancelToken : [config.cancelToken]
tokens.forEach((token) => {
token && typeof token === 'function' ? token() : cancelTokens.includes(token) && token.cancel()
})
}
return Request(config)
}
```
在这个修改后的代码中,我们创建了一个名为 `cancelTokens` 的数组,用于存储每个请求的 CancelToken。在请求拦截器中,我们将每个请求的 CancelToken 添加到这个数组中。在响应拦截器中,我们不需要对 `cancelTokens` 进行任何修改。
在导出的函数中,我们首先检查传入的配置对象中是否包含 `cancelToken` 属性。如果包含,我们先将其转化为数组,然后遍历数组中的每个元素,并调用对应的 `cancel` 函数进行取消。最后,我们返回一个 Promise 对象,用于异步请求。
axios-miniprogram Canceler 应如何导入
要在小程序中使用 `axios-miniprogram` 的 `Canceler` 类,需要先安装 `axios-miniprogram` 包。可以使用以下命令进行安装:
```
npm install axios-miniprogram --save
```
然后,在需要使用 `Canceler` 的地方,可以按照以下方式导入:
```javascript
import { Canceler } from 'axios-miniprogram';
```
然后就可以使用 `Canceler` 类来创建一个取消请求的对象。例如:
```javascript
const cancelToken = axios.CancelToken;
const canceler = new cancelToken.source();
```
这里的 `cancelToken` 是 `axios-miniprogram` 中的一个工厂函数,用于创建 `CancelToken` 类的实例。`canceler` 则是一个 `CancelToken` 类的实例,用于创建取消请求的对象。
阅读全文