AbortController

792 阅读3分钟

AbortController

AbortController 是一个在现代浏览器中内置的 API,用于取消任何正在进行的请求。Axios 提供了一个 signal 选项来使用 AbortController API。

传送至官网: 取消请求 | Axios Docs (axios-http.com)

下面是如何在 Axios 请求中使用 AbortController :

javascript复制代码 const controller = new AbortController();
 
 axios.get('/foo/bar', {
    signal: controller.signal
 }).then(function(response) {
    //...
 });
 
 // 取消请求
 controller.abort();

通过使用 AbortController 的实例,我们可以在需要时调用 abort() 方法来取消请求。

在 Axios 中,我们可以将 AbortControllerAxiosRequestConfigsignal 选项一起使用。

具体来说,我们可以为每个请求创建一个 AbortController 实例,并将其添加到请求配置中,以便我们可以随时取消请求。

封装 AbortController 的示例:

import type {AxiosRequestConfig } from 'axios'

//等待中的所有请求
const pendingMap=new Map<string,AbortController>()

function getPendingUrl(config:AxiosRequestConfig){
    return [config.method,config.url].join('&')
}

export class AxiosCancel{
    /**
    * @description: 添加请求
    * @return {*}
    */
   public addPending(config:AxiosRequestConfig){
        const url=getPendingUrl(config)
        const controller=new AbortController()
        config.signal=controller.signal
        if(!pendingMap.has(url)){
            pendingMap.set(url,controller)
        }
        console.log(pendingMap);
   }
   /**
   * @description: 清除请求
   * @return {*}
   */
   public removePending(config:AxiosRequestConfig){
    const url=getPendingUrl(config)
    if(pendingMap.has(url)){
        const controller=pendingMap.get(url)
        if(controller){
            console.log('请求取消');
            controller.abort()
        }
        //缓存列表清除
        pendingMap.delete(url)
    }
   }
   /**
   * @description: 终止一切pending请求
   * @return {*}
   */
   public removeAllPending(){
    pendingMap.forEach((item)=>{    
        if(item){
            item.abort()
        }
    })
    pendingMap.clear()
   }
}

以上提供的代码实现了一个基本的AxiosCanceler类。这个类可以用来取消正在进行的请求。在这个类中,我们创建了一个pendingMap对象,它用于存储每个请求的标识和取消函数。当请求被发出时,我们将其添加到pendingMap中。如果需要取消请求,我们可以使用AbortController.abort()方法取消请求。

在AxiosCanceler类中,我们定义了addPending、removeAllPending和removePending三个方法。addPending方法用于发送请求时,将其添加到pendingMap中。removeAllPending方法可以用于取消所有处于pending的请求,而removePending方法可以用于取消单个请求。

使用AbortCancel封装类实例

import axios from "axios";
import {AxiosCancel} from './AbortController'
import type { AxiosRequestConfig } from "axios";
export function reqTest(){
    let reqConfig:AxiosRequestConfig={method:'post',url:'/api/test'}
    //每次发送请求前,先取消缓存列表中的请求,然后重新添加
    cancel.removePending(reqConfig)
    cancel.addPending(reqConfig)
    return request<any,any>(reqConfig)
}

总结

如果你在你的应用程序中需要管理多个请求,并且需要在请求发出后取消这些请求,那么AxiosCanceler类将是一个非常有用的工具。它可以让你更好地控制你的异步请求,并避免一些不必要的错误。

二次封装的axios

//index.ts
import axios from 'axios'
import type {
  AxiosInstance,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios'
import type { RequestConfig } from './type'
class Request {
  instance: AxiosInstance
  constructor(config: RequestConfig) {
    this.instance = axios.create(config)
    this.instance.interceptors.request.use(
      (config: InternalAxiosRequestConfig) => {
        return config
      },
      (err) => {
        console.log(err)
      }
    )
    this.instance.interceptors.response.use(
      (res: AxiosResponse) => {
        return res
      },
      (err) => {
        console.log(err)
      }
    )
    /* 实例拦截器 */
    if (config.interceptors) {
      this.instance.interceptors.request.use(
        config.interceptors?.requestInterceptors,
        config.interceptors?.requestInterceptorsCatch
      )
      this.instance.interceptors.response.use(
        config.interceptors?.responseInterceptors,
        config.interceptors.responseInterceptorsCatch
      )
    }
  }

  /* 
    二次封装请求方法
    */
  request<T>(config: RequestConfig) {
    //如果请求方法里额外传递了拦截器,那么就调用,它反正还会返回对应的config的
    return new Promise<T>((resolve, reject) => {
      if (config.interceptors?.requestInterceptors) {
        config = config.interceptors.requestInterceptors(config)
      }
      //调用axios自带的request方法,最后需要resolve(T类型的值)
      this.instance.request<any, T>(config).then(
        (res) => {
          if (config.interceptors?.responseInterceptors) {
            res = config.interceptors?.responseInterceptors(res)
          }
          resolve(res)
        },
        (err) => {
          reject(err)
        }
      )
    })
  }
}

export default Request

//type.ts
import type {
  AxiosRequestConfig,
  InternalAxiosRequestConfig,
  AxiosResponse,
} from 'axios'

type instanceInterceptors = {
  requestInterceptors?: (
    config: InternalAxiosRequestConfig | AxiosRequestConfig
  ) => InternalAxiosRequestConfig
  requestInterceptorsCatch?: (err: any) => void
  responseInterceptors?: <T = AxiosResponse>(res: T) => T
  responseInterceptorsCatch?: (err: any) => any
}

export interface RequestConfig extends AxiosRequestConfig {
  interceptors?: instanceInterceptors
}

使用

//单个实例封装的拦截器
import Request from './index'
const baseRequest = new Request({
  baseURL: 'http://localhost:8080/api',
  timeout: 5000,
  interceptors: {
    responseInterceptors(res) {
      return res.data
    },
  },
})

export default baseRequest.instance

//单个请求封装拦截器
mport Request from './index'
const baseRequest = new Request({
  baseURL: 'http://localhost:8080/api',
  timeout: 5000,
})
export default baseRequest

//请求文件
import request from '../baseRequest'

type form = {
  name: string
  data: any
}

export const getLogin = () => {
  return request.request<form>({
    url: '/get',
    interceptors: {
      responseInterceptors(res) {
        return res
      },
    },
  })
}