项目中如何使用axios过滤多次重复请求详解

2022-04-15 0 998
目录
  • 一、前言:
    • 这个情况下,我们通常的做法有两种:
  • 二、CancelToken类
    • 最终效果
  • 总结

    一、前言:

    我们在web应用开发过程当中,经常会遇到一个时刻发起了多个请求的场景

    项目中如何使用axios过滤多次重复请求详解

    这个情况下,我们通常的做法有两种:

    • 可以在请求时show一个loading,阻止用户操作。
    • 或者人为加个变量,做一个请求的节流

    我们的项目中,目前大部分情况也是采用以上两种方式做的。今天来介绍一个新的方式。

    二、CancelToken类

    我们之前实例化一个Promise,这个对象是否成功与否,是无法在函数外部决定的,这里边使用要用到一个小窍门,可以让一个promise 和resolve分离。任何时机都可以触发resolve:

      // 一个promise
      let resolvePromise
      let p = new Promise((resolve, reject) => {
        resolvePromise = resolve
      })
      // 这样在外部执行
      resolvePromise()
    

    ok,有了这个前提,我们需要借助axios.CancelToken这个类。

    这个类相当于在每次请求的时候开启另一个promise和当前的请求形成一个promise.race(请求p1,取消请求p2),在promise中的resolve方法赋值给了一个外部的变量去接收。我们可以根据需求,人为决定是否取消前次请求。其实这就类似,原来我们写fetch封装接口超时的Promise.race类似。

    cancelToken中也提供了相应的static方法source用来生成一个cancelToken和一个cancel方法其实就是这个promise的一个resolve。

        CancelToken.source = function source() {
        var cancel;
        // 
        var token = new CancelToken(function executor(c) {
            cancel = c;
        });
        return {
            token: token,
            cancel: cancel,
        };
    

    根据我们常用的的缓存方式,我们可以声明一个map来存储每次请求的url,同时存储对应的cancel方法。

        // 声明一个全局map
        const pendingHttp = new Map()
        // axios中内置的CancelToken类
        const CancelToken = axios.CancelToken
           
        function addApi (config) {
          config.cancelToken = new CancelToken((cancel) => {
            const url = config.url
            console.log(pendingHttp)
            if (!pendingHttp.has(url)) {
              pendingHttp.set(url, cancel)
            }
          })
        }
    
        function cancelApi (config) {
          const url = config.url
          if (pendingHttp.has(url)) { // 如果在 pending 中存在当前请求标识,需要取消当前请求,并且移除
            const cancel = pendingHttp.get(url)
            cancel(url + '取消了')
            pendingHttp.delete(url) // 清空当前url的缓存
          }
        }
    
    • 要特殊注意,要想取消掉一个请求,需要在config上添加cancelToken这个属性赋值为CancelToken的实例。否则cancel不掉。

    就像操作定时器一样,要先尝试取消上一次,然后再开启下一次

        httpService.interceptors.request.use(config => {
    
          cancelApi(config)
          addApi(config)
          
          // 本地调试的时候,是跨域的情况,加请求头会有限制(此处是项目代码无关紧要)
          const { headers = {} } = config; const { globalObj = {} } = window
          Object.assign(headers, globalObj, { from })
          
          return config
        }, error => {
          console.log(error)
          return Promise.reject(error)
        })
    

    然后还有一种可能性,第一次请求已经返回了,又发起了相同的一次请求,所以在response里边也要cancelApi一下。

        httpService.interceptors.response.use(
          response => {
            cancelApi(response.config)
            sentryCatchApi(response)
          },
          error => {
            // 请求超时
            if (error.message.includes('timeout')) { // 判断请求异常信息中是否含有超时timeout字符串
              Toast.error({ text: '网页请求超时,请刷新重试~' })
            }
            sentryCatchApi(error)
            return Promise.reject(error)
          }
        )
    

    我们需要注意一点,cancel其实就是resolve,我们cancel执行时候传入的参数,会最终在response的error回调中,作为参数返回,这样我们的捕捉错误的方法可能会有报错。

        // 假设我们的error方法是这样封装的。 来看一下sentryCatchApi
        error => {
          sentryCatchApi(error)
          return Promise.reject(error)
        }
      // 由于这个方法需要接收一个对象,但是我们cancel取消请求的情况下,返回的是一个字符串,这时就报错了。
      function sentryCatchApi (res) {
          try {
            res = res || {}
            const resData = res.data || {}
            Sentry.captureException(JSON.stringify(resData))
            console.log(`
              获取数据失败:
              请在浏览器中打开进入 webview的地址,并粘贴出来,便于问题排查
              :接口相关信息:
              接口地址:${res.config.url},
              接口返回值:code:${resData.code},
              message:${resData.message},
              data:${JSON.stringify(resData.data)}
            `)
          } catch (err) {
            console.error(err)
          }
        }
    

    需要使用isCancel这个api

       error => {
        if (axios.isCancel(error)) return console.log('请求被取消了', error.message)
        sentryCatchApi(error)
        return Promise.reject(error)
      }
    

    最终效果

    项目中如何使用axios过滤多次重复请求详解

    控制台也没有任何报错啦。(后续完善到项目中)

    总结

    到此这篇关于项目中如何使用axios过滤多次重复请求的文章就介绍到这了,更多相关axios过滤多次重复请求内容请搜索NICE源码以前的文章或继续浏览下面的相关文章希望大家以后多多支持NICE源码!

    免责声明:
    1、本网站所有发布的源码、软件和资料均为收集各大资源网站整理而来;仅限用于学习和研究目的,您必须在下载后的24个小时之内,从您的电脑中彻底删除上述内容。 不得使用于非法商业用途,不得违反国家法律。否则后果自负!

    2、本站信息来自网络,版权争议与本站无关。一切关于该资源商业行为与www.niceym.com无关。
    如果您喜欢该程序,请支持正版源码、软件,购买注册,得到更好的正版服务。
    如有侵犯你版权的,请邮件与我们联系处理(邮箱:skknet@qq.com),本站将立即改正。

    NICE源码网 JavaScript 项目中如何使用axios过滤多次重复请求详解 https://www.niceym.com/29637.html