zoukankan      html  css  js  c++  java
  • Vue+Axios:使用拦截器来取消多次重复的请求

    -----写在前面-----

    家园的面试项目接近尾声了,剩下一个大模块(响应式布局)和两个小功能(下拉到一定程度获取新的信息、持续监听返回数据,当有更新时在页面上方提示)

    听起来下拉到某个位置获取新信息是不难,但今天就遇到了两个问题:

    1. 下拉过程中会不断发起url相同的请求,可能会有被拉黑的风险,并且影响实际性能。最重要的,在then()方法中会将返回数据稍做处理后添加进组件数据,并且会驱动Vue更新DOM,

    因为用的v-for来填充数据,这样同一条数据就会被渲染两次

    2.ReadHub除了topic栏外,其余四个栏目下拉获取更新数据的api接口地址中的参数是时间戳!!而且返回的数据长度也不同

    这就导致除了topic以外的栏目在获取更新数据后还要和已有的数据进行比对,不能重复,目前的想法是

    在负责更新数据的axios.then()方法中,detail(存储所有数据)转set结构,然后把新返回的数据push进去,再转回数组(也可以不转回去?)

    ⬆⬆⬆⬆⬆这个想法无法执行,因为很神奇的,同样的api接口可能返回两种不同格式的数据

    第0条和第10条的数据是一样的(以此类推...)。而且我暂时没有找到剩下的四个栏目,更新列表发起的请求地址中的时间戳是哪里来的??

    (topic栏目是直接根据未加载时列表最下方的一条数据的order来请求的)

    而且这个时间戳也没有规律啥的...

    这篇博客主要解决问题1,即拦截相同url的axios请求,网上教程是一堆,但好像大家都是从同一份魔改出来的?因此我头皮发麻的想了好久,在思否的提问只有21个浏览...

     

    推荐阅读Axios的中文文档

     

    首先需要明白拦截器的工作原理,axios中内置了两个拦截器,请求拦截器与响应拦截器,分别通过以下两个方法调用

    axios.interceptors.request.use()
    axios.interceptors.response.use()


    拦截器的触发:

    对于单个请求来说,在请求发送后会触发request拦截器进行拦截。

    因此可以有以下思路,建立一个空数组,第一次请求成功发送后将本次请求的url保存起来,下一次再次发送请求,会先在请求拦截器中检验这一请求的url是否在这个数组中被保存了,

    如果是,则取消本次请求(AXIOS提供了cancelToken来取消请求,详见后文)。

    如果有需要的话,在响应拦截器中,在成功返回响应后将本次请求的url从数组中去掉,以便后续的使用,这一情况适用于防止用户多次点击发送重复请求?即这个接口后面还有可能用到

            let pending = []; //声明一个数组用于存储每个请求的取消函数和axios标识
                let cancelToken = axios.CancelToken;
                let removePending = (config) => {
                    // console.log(config);
                    for(let i in pending){
                        if(pending[i].url === axios.defaults.baseURL+config.url) { //在当前请求在数组中存在时执行取消函数
                            pending[i].f(); //执行取消操作
                            //pending.splice(i, 1); 根据具体情况决定是否在这里就把pending去掉
                            console.log(pending[i].url);
                        }
                    }
                }

    请求拦截器与响应拦截器:

    axios.interceptors.request.use(config => {
                    removePending(config); //在一个axios发送前执行一下判定操作,在removePending中执行取消操作
                    // console.log(config.url);
                    config.cancelToken = new cancelToken(function executor(c){//本次axios请求的配置添加cancelToken
                    pending.push({
                        // url: config.url,
                        url: axios.defaults.baseURL+config.url,
                        f:c
                    }); 
                    // console.log(axios.defaults.baseURL+config.url);
                    //将本次的url添加到pending中,因此对于某个url第一次发起的请求不会被取消,因为还没有配置取消函数
                });
                    return Promise.resolve(config);
                }, error => {
                    return Promise.reject(error)
                })
                axios.interceptors.response.use(data => { 
                    // removePending(data.config); //在一个axios响应后再执行一下取消操作,把已经完成的请求从pending中移除
                    // console.log(data.config);//如果返回undefined说明被拦截了
                    return Promise.resolve(data)
                    
                    }, error => {
                    //加载失败
                    return {'data':{}}
                    })

    这里的详解见上面的axios中文文档哈,如果懒得看只要知道这里的c是new cancelToken构造器生成的取消函数就行。

     注意这里两行不同的url,使用上面一行会导致无法拦截,因为项目前面手动设置了axios.defaults.baseURL,导致这里传入的url如果不加上baseURL,就只会是/topic?lastCursor=xxxxxx&pageSize=20,

    但在pending数组⬇中的则是完整的url,就会导致url不匹配从而无法拦截。

    建议把这里注释掉的控制台打印代码好好运行几遍~

  • 相关阅读:
    测试sql 查询时间
    C# 数组 ArrayList Array 在C#里把ArrayList转换为Array 或 把Array转换为ArrayList
    DotNet软件开发框架
    C# Socket多线程编程实例
    Yahoo!网站性能最佳体验的34条黄金守则
    最基本的Socket编程(C#)
    完全解决VS2008通过Internet连接VSS2005
    追MM与设计模式的有趣见解
    一个GridView的PagerTemplate
    线程
  • 原文地址:https://www.cnblogs.com/linbudu/p/11259070.html
Copyright © 2011-2022 走看看