axios取消接口请求

自己碰到的问题,扒了很多文档才理清楚,当做是笔记记下来
说到取消接口请求,可能没碰到这样的坑冷不丁还有点懵,为什么会有取消请求这回事,既然决定要请求这个接口了又要取消它,岂不是有点画蛇添足的操作?


1.应用场景,为什么要取消请求
我给你这样一个场景你变能理解为什么需要取消请求这种骚操作了(非常常见的场景,这里是用vue写的)

这是一个tab切换页

并且这是一个只有一个dom结构的tab页,也就会说当前显示的是 “通知” 页,“动态”和“系统公告”其实此刻是没有专属的dom结构的,当点击“动态”页的时候“通知”页的数据消息,将获取到的“动态”页的数据渲染到dom上,也就是说,这里的数据都是本地同一个数组盛放的。为什么这么写,因为这里的每个tab的结构都长的很相似,没有必要去写3个dom用来盛放数据,这样代码更简洁。(我为什么要解释这样的东西?emmmm.....)

好的!问题来了!!!当我点击动态栏的时候,这个时候向后台传输一个id=2的参数,通过ajax获取当参数为2的时候的数据,然后在将原本参数为1的tab页的数据清空(默认进来展示的tab1),渲染tab2的页面,我们知道ajax是异步操作的,当接口优化没做好,或者获取的数据过多或者用户网速较差的时候,这个获取数据的ajax操作需要一定的时间来将数据拿到再渲染到页面上,在这个时间段内,如果我再次点击tab3也就是“系统公告”的时候,代码又将id=3的参数传给后台,去获取tab3的数据,而id=2的时候的接口数据或许还在从服务器回到前台的路上,那这个时候,就想从tab1到tab2一样的我们去清空数组中盛放的tab2的数据,清空的是什么?tab2的数据还在返回来的路上还没被push进数组呢!所以这里我们清空了一次空数组!!!那我们就会看到,此时我们页面是处在tab3了,里面的数据因为是被push进去我们本地用来盛放数据的数组的,所以,此时的数据会是id=2的数据 && id=3的数据,这样,问题就暴露出来了!

总感觉自己说了一大堆废话emmmm...那既然问题出来了,我们肯定要解决这个问题的,我们理想的的解决问题的思路应该是 > 现在我得到的数据多余我要的 > 多出来的数据是因为上一个tab页请求延迟造成的 > 那我们就在确定拿到数据的时候再清空数组就好了!

对,没错,ajax resolved中去清除数组中的数据,这样就防止了清除操作执行数据还没请求过来的意外了!

不过因为需求问题,我这里不能这样操作,每个tab页面都是可以上下滚动的,上拉加载更多,如果在resolved中去清除原有数据的话,上来加载更多的时候再下拉就看不到上一页的数据了,被清除了,所以我这里只能另想办法了。。。。

找到一条思路 > 现在我得到的数据多余我要的 > 多出来的数据是因为上一个tab页请求延迟造成的 > 那我就在当前页请求数据的时候掐断上一个页面还没完成的请求就好了

于是开启了扒文档之路。。。

这里就是分析一下接口请求需要被取消时的一些操作(化身超人啦啦啦)

因为我是用vue写的项目,所以标配用的是axios,怎么在axios中取消已经发送的请求呢?

2.在这之前我们还是先介绍一下原生js的abort()这个方法。

直接上代码会比较好一点

<div class="page" id="app">
    <button  class="get-msg">获取数据</button>
    <button  class="cancel">取消获取</button>
  </div>
<script>
  var currentAjax = null
    $('.get-msg').click(function () {
      currentAjax = $.ajax({
        type: 'GET',
        url: 'http://jsonplaceholder.typicode.com/comments',
        success: function (res) {
          console.log(res)
        },
        error: function (err) {
          console.log("获取失败")
        }
      })
    })
    $('.cancel').click(function () {
      if (currentAjax) {
        currentAjax.abort()
      }
    })
  </script>

点击获取数据按钮打印出来的数据
点击获取数据之后~超超超快快快~的手速点击取消获取按钮打印出来的效果

看这两张效果图就知道,我们的abort()方法起作用了!!!!


3.在axios中取消接口请求操作

好了,接下来才是我们的主题,Axios官方提供了一个取消接口请求的方法,但是怎么用这个方法官网写的很简略(不知道是不是我没找全的问题),反正官网的axios取消接口请求累的半死没看懂,后来是扒了很多大佬的博客,才自己理解出来的
Axios 提供了一个 CancelToken的函数,这是一个构造函数,该函数的作用就是用来取消接口请求的,至于怎么用,看代码吧,我在代码中写了注解

<body>
  <div class="page" id="app">
    <button @click="getMsg" class="get-msg">获取数据</button>
    <button @click="cancelGetMsg" class="cancel">取消获取</button>
    <ul>
      <li v-for="item in items">{{item.name}}</li>
    </ul>
  </div>
  <script>
  var app = new Vue({
    el: '#app',
    data: {
      message: 'Hello Vue!',
      items: [],
      cancel: null
    },
    methods: {
      getMsg () {
        let CancelToken = axios.CancelToken
        let self = this
        axios.get('http://jsonplaceholder.typicode.com/comments', {
          cancelToken: new CancelToken(function executor(c) {
            self.cancel = c
            console.log(c)
            // 这个参数 c 就是CancelToken构造函数里面自带的取消请求的函数,这里把该函数当参数用
          })
        }).then(res => {
          this.items = res.data
        }).catch(err => {
          console.log(err)
        })


        //手速够快就不用写这个定时器了,点击取消获取就可以看到效果了
        setTimeout(function () {
          //只要我们去调用了这个cancel()方法,没有完成请求的接口便会停止请求
          self.cancel()
        }, 100)
      },
      //cancelGetMsg 方法跟上面的setTimeout函数是一样的效果,因为手速不够快,哦不,是因为网速太快,导致我来不及点取消获取按钮,数据就获取成功了
      cancelGetMsg () {
        // 在这里去判断你的id 1 2 3,你默认是展示的tab1,点击的时候不管你上一个请求有没有执行完都去调用这个cancel(),
        this.cancel()
      }
    }
  })
  </script>
</body>

上两张效果图展示一下:


点击获取数据按钮获获取到了数据

点击获取数据之后,用快快快的佛山无影手点击了取消获取得到的效果

这样,就完美的解决了我遇到的问题了,点击tab切换的时候,网络敢延迟,我就敢掐掉你的请求,保证我下一个请求不被影响


4.重复点击问题

那我们经常开发的时候会遇到一个重复点击的问题,短时间内多次点击同一个按钮发送请求会加重服务器的负担,消耗浏览器的性能,多以绝大多数的时候我们需要做一个取消重复点击的操作
在vue开发中,这个方法一样完美解决这一问题,通常我们会封装一遍axios,这里我们便可以将此功能封装到拦截器里面去

    import axios from 'axios';
    
    axios.defaults.timeout = 5000;
    axios.defaults.baseURL ='';

    let pending = []; //声明一个数组用于存储每个ajax请求的取消函数和ajax标识
    let cancelToken = axios.CancelToken;
    let removePending = (ever) => {
        for(let p in pending){
            if(pending[p].u === ever.url + '&' + ever.method) { //当当前请求在数组中存在时执行函数体
                pending[p].f(); //执行取消操作
                pending.splice(p, 1); //把这条记录从数组中移除
            }
        }
    }
    
    //http request 拦截器
    axios.interceptors.request.use(
    config => {
      config.data = JSON.stringify(config.data);
      config.headers = {
        'Content-Type':'application/x-www-form-urlencoded'
      }
      // ------------------------------------------------------------------------------------
      removePending(config); //在一个ajax发送前执行一下取消操作
      config.cancelToken = new cancelToken((c)=>{
         // 这里的ajax标识我是用请求地址&请求方式拼接的字符串,当然你可以选择其他的一些方式
         pending.push({ u: config.url + '&' + config.method, f: c });  
      });
      // -----------------------------------------------------------------------------------------
      return config;
    },
    error => {
      return Promise.reject(err);
    }
  );
  //http response 拦截器
  axios.interceptors.response.use(
    response => {
      // ------------------------------------------------------------------------------------------
      removePending(res.config);  //在一个ajax响应后再执行一下取消操作,把已经完成的请求从pending中移除
      // -------------------------------------------------------------------------------------------
      if(response.data.errCode ==2){
        router.push({
          path:"/login",
          querry:{redirect:router.currentRoute.fullPath}//从哪个页面跳转
        })
      }
      return response;
    },
    error => {
      return Promise.reject(error)
    }
  )

这是我自己项目用来封装axios的代码,里面加入了取消重复点击事件的方法(灵感来源于 大田角https://www.jianshu.com/p/4445595488e2),以后写项目一劳永逸啦,妈妈再也不用担心我的代码重复请求的问题啦!!!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,271评论 5 476
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,275评论 2 380
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,151评论 0 336
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,550评论 1 273
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,553评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,559评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,924评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,580评论 0 257
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,826评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,578评论 2 320
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,661评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,363评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,940评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,926评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,156评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,872评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,391评论 2 342

推荐阅读更多精彩内容

  • Android 自定义View的各种姿势1 Activity的显示之ViewRootImpl详解 Activity...
    passiontim阅读 171,387评论 25 707
  • 用两张图告诉你,为什么你的 App 会卡顿? - Android - 掘金 Cover 有什么料? 从这篇文章中你...
    hw1212阅读 12,680评论 2 59
  • 苹果前段时间要求上架的应用都要支持https协议,并为此设计了ATS这个配置项。具体来说就是,应用默认是不支持ht...
    秦砖阅读 380评论 0 0
  • 李芳是一位中学教师,贤惠温柔,举手投足给人一种典雅的淑女风范。 工作中李芳一直兢兢业业,不断努力进行业务学习,来提...
    LH来慧阅读 1,707评论 22 40
  • 题记 季羡林其人,资料简介 读书篇 外语学习 季羡林老先生在这本书里谈德国的外语教学方法时,提到一个德国的东方学教...
    一路安顺阅读 714评论 0 1