美文网首页
axios取消请求的实现

axios取消请求的实现

作者: chiugi | 来源:发表于2021-09-08 19:44 被阅读0次

    简述

    文档处提到两种撤销请求的方式,可满足各种取消请求的场景

    单个接口取消

    通过传递一个 executor 函数到 CancelToken 的构造函数来创建一个 cancel token
    interface.js

    import axios from 'axios'
    
    export function getXXX(data, that = {}, cancelFuncName = 'cancel') {
      return request({
        timeout: 6000,
        url: '/xxxx',
        method: 'post',
        data,
        cancelToken: new axios.CancelToken(function executor(c) {
          that[cancelFuncName] = c
        }),
      })
    }
    
    

    多个接口同时取消

    使用 CancelToken.source 工厂方法创建一个 cancel token,借助vuex和vue-router处理页面跳转的接口
    interface.js

    
    import axios from 'axios'
    // 初始化取消请求对象
    const CancelToken = axios.CancelToken
    const source = CancelToken.source()
    
    export function getXXX(data) {
      return request({
        url: '/xxx,
        method: 'post',
        data,
        cancelToken: source.token,
      })
    }
    
    

    store.js

    import Vuex from 'vuex'
    
    const store = new Vuex.Store({
      state: {
        source: {
          token: null,
          cancel: null,
        },
      },
    })
    
    export default store
    

    router.js

    import router from './router'
    import axios from 'axios'
    import store from './store'
    router.beforeEach(async(to, from, next) => {
            const CancelToken = axios.CancelToken
            store.state.source.cancel && store.state.source.cancel()
            store.state.source = CancelToken.source()
            next()
    })
    

    request.js

    import store from '@/store'
    import axios from 'axios'
    
    const service = axios.create({
      baseURL: process.env.VUE_APP_BASE_API, 
    })
    
    service.interceptors.request.use(config => {
        // 初始化axios中的cancelToken 
        config.cancelToken = store.source.token
        return config
    }, err => {
        return Promise.reject(err)
    })
    
    

    封装CancelToken

    
    import axios from 'axios'
    
    export default class CancelToken {
      // 声明一个 Map 用于存储每个请求的标识 和 取消函数
      static pending = new Map()
      // 白名单, 写入接口名称
      static whiteRequest = []
    
      /**
       * 得到该格式的url
       * @param {AxiosRequestConfig} config
       * @returns
      */
      static getUrl(config) {
        return [config.method, config.url].join('&')
      }
    
      /**
       * 添加请求
       * @param {AxiosRequestConfig} config
      */
      static addPending(config) {
        const url = this.getUrl(config)
        config.cancelToken = new axios.CancelToken(cancel => {
          if (!this.pending.has(url)) { // 如果 pending 中不存在当前请求,则添加进去
            this.pending.set(url, cancel)
          }
        })
      }
    
      /**
       * 移除请求
       * @param {AxiosRequestConfig} config
      */
      static removePending(config) {
        const url = this.getUrl(config)
        const method = url.split('&')[1]
        console.log(method)
        if (this.pending.has(url) && !this.whiteRequest.includes(method)) { // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
          const cancel = this.pending.get(url)
          cancel(url)
          this.pending.delete(url)
        }
      }
      /**
       * 清空 pending 中的请求(在路由跳转时调用)
      */
      static clearPending() {
        for (const [url, cancel] of this.pending) {
          cancel(url)
        }
        this.pending.clear()
      }
    }
    

    用法:

    
    service.interceptors.request.use(
      config => {
        // 这里的判断用于处理白名单不参与取消请求
        if (!CancelToken.whiteRequest.includes(`${config.url}`)) {
          // 请求开始前,检查一下是否已经有该请求了,有则取消掉该请求
          CancelToken.removePending(config)
          // 把当前请求添加进去
          CancelToken.addPending(config)
        }
        return config
      },
      error => {
        // do something with request error
        console.log(error) // for debug
        return Promise.reject(error)
      },
    )
    
    instance.interceptors.response.use((resp: AxiosResponse<IResponse>) => {
      // 接口响应之后把这次请求清除
      CancelToken.removePending(resp.config)
      if(resp.data.status === 200) {
        // 接口请求成功
        return resp.data.data
      }
      return Promise.reject('')
    })
    
    router.beforeEach((to, from, next) => {
      // 路由跳转要清除之前所有的请求缓存
      CancelToken.clearPending()
      next()
    })
    

    参考地址:
    浅显易懂的Axios源码解析并封装CancelToken类

    相关文章

      网友评论

          本文标题:axios取消请求的实现

          本文链接:https://www.haomeiwen.com/subject/fmzvwltx.html