最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 从缓存接口到axios节流

    正文概述 掘金(waynetang)   2021-01-06   591

    在我们的工程中,很有可能碰到一种情况那就是不同的组件几乎在同样的时间加载然后用到了同样的url和参数,然后造成了同样的请求,所以我们可以设置一个缓存接口,这个缓存接口调用后会返回一个函数,我们再通过这个函数去请求具体的后台,所以使用起来是这样的

    const request = window_it(20)  //20ms之内
    request("....").then(resp=>{    //请求1
        console.log(resp)
    }) 
    request("....").then(resp=>{    //请求2
        console.log(resp)
    })
    

    这个window_it的实现我们需要给一个时间窗口,在20ms内相同的请求就直接只发一条,所以实现起来是这样的,代码简写,重点看个思路

    function window_it(time){
        let map = new Map()
        let flag = true
        return function request(...args){
              return new Promise((reslve,reject)=>{
                    let key = hash(...args)     //用参数来拿到hash
                    if(!map.has(key)){
                          map.set(key,{args,resolves:[resolve],rejects:[rejects]})
                    }else{
                        //如果已经有相同的hash了,那么就把resolve存起来
                        map.get(key).resolves.push(resolve)
                        map.get(key).rejects.push(reject)
                    }
                    if(flag){
                        flag= false
                        setTimeout(()=>{
                             for(let [key,value] of map){
                                let { args, resolves } = value
                                fetch(...args).then(value=>{
                                    resolves.forEach(r=>{
                                        r(value)
                                    })
                                    map.delete(key)     //遍历完就删掉
                                },error=>{reject(error)})
                             }
                            flag = true
                        },time)          
                    }
              })
        }
    }
    

    -----------------------------------分割线-----------------------------------------------------

    但是实际工作中我们一般都使用主流的axios,所以我们需要把上述的逻辑给放到axios的interceptors里面去,在reuest.interceptors里面,我们必然要把上面的逻辑给放进去,但是碰到

    已经有重复参数的请求,可以直接就调用axiso提供的cancel方法,把这个方法给直接取消掉,这样这个借口直接就不会发出去了,然后在时间窗口参数中去把map的resolves都给往下跑

    所以第一部分我们先完成axiso.interceptors.request的部分,其实跟上面的代码差不多,

    但是要注意没重复的接口给个config.myHash和重复的接口给个cancelReason,

    这样的话res那里当做key用

    let map = new Map()
    let flag = true
    let cancel
    let DUPLICATE = "duplicate request :"   //这里以冒号分割
    function hash(config){
          return JSON.stringify(config)     //这里直接以json来为例,可根据实际情况定
    }axios.interceptors.request.use((config)=>{
        return new Promise(resolve=>{
              let key = hash(config)
              config.myHash = key             //这里给到key,这样res的时候可以作为key
              if(map.has(key)){
                   map.set(key,{config,resolves:[resolve]})
               }else{
                   //如果发现有重复的直接cancel
                   config.cancelToken = new axios.CancelToken(c=>{
                       cancel =c
                   })
                   cancel(DUPLICATE + key)    //这里给一个cancel的信息,reject的时候会拿到,作为key
                   map.get(key).resolves.push(resolve)
               }
              if (flag) {            setTimeout(() => {               flag = false               for (let [key, value] of map) {                   let { config, resolves } = value                    resolves.forEach(r => {                       r(config)                       map.delete(key)                    })               }               flag = true            }, 200)         }      })
    })
    

    这样的话我们必然会在response.interceptors中会收到取消掉的信息,但是需要注意的是取消的接口会在请求的接口前面先回来

    比如,我们第一个请求是axios.get("a",{params:{a:1}}),第二个请求也是axios.get("a",{params:{a:1}}),这时候发现拦截器发现重复了,但是我们在aixos.interceptors.response里面的拦截器一定会先收到第二个重复请求的reject,

    因为其实在axios的源码中的xhr.js如果碰到了config.cancelToken发现有token就直接rejct,请求都不用发,所以肯定是快的,所以我们需要再来一个respMap来存储key,然后等待第一个不重复的请求的数据value回来,再去resolve(value),来实现重复的接口请求也能拿到数据的效果

    let resMap = new Map()
    axios.interceptors.response.use(resp=>{
        return new Promise(resolve=>{
            let key
            if(key = resp.config.myHash){    //成功了就看有没有我们自己添加的key
                resMap.has(key) && resMap.get(key).resolves.push(resolve)
                resMap.get(key).resolves.forEach(r=>{
                    r(resp)
                })
            }else{
                resolve(resp)
            }
        })
    },error=>{
        //这里必须要返回一个promise,然后把resolve给放到resMap里面去
        return new Promise(resolve=>{
            if(error instanceof axios.Cancel && error.message.indexOf(DUPLICATE) > -1){            //如果发现error是个CANCEL
                let key = error.message.replace(DUPLICATE,"")
                if(!resMap.has(key)){
                    resMap.set(key,{
                        reolves:[resolve],
                        rejects:[rejects]
                    })
                }else{
                    ...                  //错误暂时省略
                }
            }  
        }) 
    })
    

    起源地下载网 » 从缓存接口到axios节流

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元