编者按:本文作者舒丽琦,奇舞团前端开发工程师

在我们web开发过程中,很多地方需要我们取消重复的请求。但是哪种场合需要我们取消呢?我们如何取消呢?带着这些问题我们阅读本文。

阅读完本文,你将了解以下内容:

  • 需要取消重复请求的场景

  • 我们如何取消重复请求

  • axios如何取消重复的请求

  • 封装axios

  • 如何给开源的项目提供源码

  • 如何在本地调试npm包

提出问题

最近做的项目中,用的用户经常遇到这样的问题:

  • 用户频繁切换筛选条件去请求数据,初次的筛选条件数据量大。用的时间比较多。后面的筛选条件的数据量小。导致后面请求的数据先返回。内容先显示在页面上。但是等一段时间,初次(或者前面)的请求数据返回了, 会覆盖后面的请求的数据。这就导致了筛选条件和内容不一致的情况。

  • 用户点击了一次提交按钮,接口没有很快响应,导致页面没办法做逻辑语句判断的提示。用户觉得可能没提交上,便会快速又点了按钮几次。如果后端没有去重的判断,就会导致数据中有很多条重复的数据。

这些问题给用户的体验是很不友好的。那么取消无用的请求是很有必要的。

解决思路

我们用的请求库是axios。那么我们可以在请求的时候拦截请求判断当前的请求是否重复,如果重复我们就取消当前的请求。大致的实现过程如下:

我们把目前处于pending的请求存储(假如我们放在一个数组)起来。每个请求发送之前我们都要判断当前这个请求是否已经存在于这个数组。如果存在,说明请求重复了,我们就在数组中找到重复的请求并且取消。如果不存在,说明这个请求不是重复的,正常发送并且把这个请求api添加在数据中,等请求结束之后删除数组中的这个api。

我们这个解决思路有了,但是axios如何取消请求的呢?我们先来了解下

axios 如何取消请求

查看axios文档发现axios提供了两种取消请求的方法(http://www.axios-js.com/zh-cn/docs/#%E5%8F%96%E6%B6%88)

  • 第一种方法

    通过axios.CancelToken.source生成取消令牌token和取消方法cancel

    const CancelToken = axios.CancelToken;

    const source = CancelToken.source();

    axios.get('/user/12345', {

      cancelToken: source.token

    }).catch(function(thrown) {

      if (axios.isCancel(thrown)) {

        console.log('Request canceled', thrown.message);

      } else {

        // 处理错误

      }

    });

    axios.post('/user/12345', {

      name: 'new name'

    }, {

      cancelToken: source.token

    })

    // 取消请求 (消息参数是可选的)

    source.cancel('Operation canceled by the user.');

  • 第二种方式

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

    const CancelToken = axios.CancelToken;

    let cancel;

    axios.get('/user/12345', {

      cancelToken: new CancelToken(function executor(c) {

        // executor 函数接收一个 cancel 函数作为参数

        cancel = c;

      })

    });

    // 取消请求

    cancel();

封装axios

解决取消请求的思路有了,取消请求的办法也有了,那么剩下的就是封装了

由于同事之前已经封装了axios——very-axios(https://github.com/verymuch/very-axios) (基于 axios 进行二次封装,更简单、更统一地使用 axios)。那么我们就这个基础上提一个pr吧。那么从现在开始我们就一步一步的来实现,这个过程包含了【如何给开源的项目贡献代码】【如何在本地调试npm】如果已经了解的同学可以直接略过。

准备工作

由于同事已经封装了axios并且已经开源了。那么我贡献代码的方式主要有两种:

  • 代码仓库的管理者给我们添加这个仓库的写入权限,如果这样,我们就可以直接提push。

  • 如果我们没有权限(大多数情况)。我们使用经典的fork & pull request 的方式来提交代码。

我们采用的第二种方式。我们去 very-axios(https://github.com/verymuch/very-axios) 把代码fork到自己的仓库(如果你还没有自己的github,需要自己注册下哦)。

那么你回到自己的github仓库下面就会看有一个一摸一样的项目

那么我们现在就可以git clone这个仓库的代码到本地,新建branch进行开发,就比如我新建了一个这样的branch:

现在已经有本地的代码了,但是我们如何本地化调试npm包呢?那就需要npm link 了

首先在我们要修改的npm 包中npm link:

之后我们会得到

/Users/shuliqi/.nvm/versions/node/v12.17.0/lib/node_modules/very-axios -> /Users/shuliqi/study/axios/very-axios

这意思就是我们把very-axios链接到全局的node_modules

然后我们进入我们my-project-of-axios 目录下面执行npm link very-axios 如图:

这意思就是very-axios被安装在my-project-of-axios 下面了。very-axios的修改都会同步到my-project-of-axios。就实现本地测试了。

我们在my-project-of-axios中的HelloWorld.vue文件中做列子。

如果这里看的不是很懂的同学可以看看这两篇文章:如何在本地调试npm包(https://github.com/allenGKC/Blog/issues/13)。如何使用 GitHub Flow 给开源项目贡献代码(https://juejin.im/post/6844903636863041550)

开始封装

准备工作完成了, 那我们开始封装的事情。根据我们之前的思路。我们采用axios 如何取消请求的第一种方式。

声明一个Map。用来存储每个请求的 标识 和 取消的函数

// 存储每个请求的标识和取消的函数

this.pendingAjax = new Map();

自定一个字段来让用户自己决定是否需要取消重复的请求

// 是否取消重复的请求

cancelDuplicated = false,

自定一个字段来让用户是否有全局的统一的设置重复标识的函数。如果没有设置全局的统一的函数,则默认是请求的method 和url作为重复的标识

// 生成重复标识的方式

duplicatedKeyFn,

this.duplicatedKeyFn = isFunction(duplicatedKeyFn) ? duplicatedKeyFn : (config) => `${config.method}${config.url}`;

添加请求

/**

 * 将请求添加到pendingAjax

 * @param {Object} config

 */

addPendingAjax(config) {

  // 是否需要取消重复的请求

  if (!this.cancelDuplicated) return

  const veryConfig = config.veryConfig || {};

  const duplicatedKey = JSON.stringify({

    duplicatedKey: veryConfig.duplicatedKey || this.duplicatedKeyFn(config),

    type: REQUEST_TYPE.DUPLICATED_REQUEST,

  });

  config.cancelToken = config.cancelToken || new axios.CancelToken((cancel) => {

    // 如果pendingAjax中不存在当前请求,添加进去

    if (duplicatedKey && !this.pendingAjax.has(duplicatedKey)) {

      this.pendingAjax.set(duplicatedKey, cancel);

    }

  });

}

这里面我们可以使用duplicatedKey字段来让用户对单一请求自定义重复的标识。或者可以使用一个函数duplicatedKeyFn统一的让用户自定义重复的标识

删除请求

/**

   * 从pendingAjax中删除请求

   * @param {Object} config

   */

  removePendingAjax(config) {

    // 是否需要取消重复的请求

    if (!this.cancelDuplicated) return

    const veryConfig = config.veryConfig || {};

    const duplicatedKey = JSON.stringify({

      duplicatedKey: veryConfig.duplicatedKey || this.duplicatedKeyFn(config),

      type: REQUEST_TYPE.DUPLICATED_REQUEST,

    });

    // 如果pendingAjax中存在当前请求, 取消当前请求并将其删除

    if (duplicatedKey && this.pendingAjax.has(duplicatedKey)) {

      const cancel = this.pendingAjax.get(duplicatedKey);

      cancel(duplicatedKey);

      this.pendingAjax.delete(duplicatedKey);

    }

  }

封装好了, 我们在哪里使用呢?肯定是在请求开始之前和请求完成之后使用。

在请求之前

// 拦截请求

this.axios.interceptors.request.use((config) => {

  // 在请求开始之前检查先前的请求

  this.removePendingAjax(config);

  // 将当前请求添加到pendingAjax

  this.addPendingAjax(config);

  // ...

});

在请求完成之后去掉该请求

// 拦截响应

this.axios.interceptors.response.use(response => {

  removePending(response)

  return response

}, error => {

  // ...

})

到现在已经完成了该有的功能, 但是取消请求的错误我们不该返回给用户。所以:

(err) => {

// 类型是否为重复请求

let isDuplicatedType;

try {

  const errorType = (JSON.parse(error.message) || {}).type

  isDuplicatedType = errorType === REQUEST_TYPE.DUPLICATED_REQUEST;

} catch (error) {

  isDuplicatedType = false

}

if (isDuplicatedType) return;

}

我们在请求完成之后的err里面做一个判断,判断如果当前请求是取消的类型,我们就不返回给用户错误的提示信息。

总结

至此,完成了我们的封装。完成的pr地址:(https://github.com/verymuch/very-axios/pull/1)。本文测试npm包的项目地址:(https://github.com/shuliqi/my-project-of-axios)

关于奇舞周刊

《奇舞周刊》是360公司专业前端团队「奇舞团」运营的前端技术社区。关注公众号后,直接发送链接到后台即可给我们投稿。

axios delete有请求体吗_封装 axios 取消重复请求相关推荐

  1. 单页面axios_Axios封装之取消重复请求和接口缓存

    在平时的单页面项目里,大家肯定接触过axios库,一个易用.简洁且高效,使用Promise管理异步,告别传统callback方式的http库. 最近有个项目里接口调取的频率比较高,接口队列长,然后等待 ...

  2. php多次请求只执行最后一次,取消重复请求,只让最后一次请求通过

    axios 请求拦截 取消重复请求(多次重复异步,结束pending状态) 前端开发中,会涉及很多异步事件处理,页面展示的处理关系最密切的就是loading图层,但是loading交互在一些时候会不太 ...

  3. axios delete有请求体吗_关于axios请求——delete方法

    有的人只知道delete方法,传值的时候,将请求值放在url上,而像post方法那些,带有请求体,却不知道该如果传值. 首先,delete方法有三种写法 一:请求参数拼接在url上 axios.del ...

  4. 封装 axios 取消重复请求

    编者按:本文作者舒丽琦,奇舞团前端开发工程师 在我们web开发过程中,很多地方需要我们取消重复的请求.但是哪种场合需要我们取消呢?我们如何取消呢?带着这些问题我们阅读本文. 阅读完本文,你将了解以下内 ...

  5. 关于 axios 取消重复请求的分析

    前言 关于取消重复请求,最重要的是这么做的意义,而不在于代码的实现 其实,我觉得,绝大部分能够想到的应用场景,都可以通过防抖.节流方式实现,比如实时搜索,比如重复订单提交.比如上拉获取最新数据等 我们 ...

  6. 400错误请求怎么解决_什么是400错误请求错误(以及如何解决)?

    400错误请求怎么解决 A 400 Bad Request Error occurs when a request sent to the website server is incorrect or ...

  7. 接口请求两次_事故分享之接口请求顺序错乱

    后发的请求先到,先发的请求后到,还有这等事?一起看看占坑防重大法. | 更多事故分享,请锁定公众号:甲蛙全栈 | 01 开篇 之前分享过一篇文章<资深码农给新手的一些建议--项目开发>,里 ...

  8. java post 请求体构建_java – 从HttpServletRequest获取POST请求体

    我试图从HttpServletRequest对象获取整个身体. 我正在关注的代码如下所示: if ( request.getMethod().equals("POST") ) { ...

  9. 小程序开发API之网络请求wx.reques、RequestTask网络请求任务对象及监听取消网络请求

    wx.request(Object object) 发起 HTTPS 网络请求.使用前请阅读 网络的使用及注意事项 wx.request参数 object.method 的合法值 object.dat ...

最新文章

  1. Rainmeter 一部分 语法 中文教程
  2. asppython份额_2019年7月编程语言榜单公布:Python第一 份额保持较大幅度增长
  3. python3.7.2使用-centos7系统下python2与python3共存
  4. (五十九)自动存储、静态存储、动态存储
  5. java什么叫内部对象,java – 函数对象的内部类中的变量/对象会发生什么?
  6. WebService事务处理
  7. Django2.x中url路由的path()与re_path()参数解释(亲测)
  8. Android开发基础(四大组件及Intent)
  9. 什么是Web渗透测试
  10. 比较两个日期oracle,在oracledb中比较两个日期并不能得到正确的结果
  11. linux源代码剖析之kernel
  12. Mac系统辅助键盘怎么开启
  13. 小白能读懂的 《手把手教你学DSP(TMS320X281X)》第七章 CPU定时器
  14. 《凤凰项目:一个IT运维的传奇故事》读书笔记
  15. matlab中pwm占空比计算代码,如何计算pwm波占空比
  16. hdu4311 Meeting point-1 求最小的曼哈顿距离和
  17. mysql查询所有学生各科成绩按照总成绩降序排列
  18. ksql kafka
  19. C语言BCC异或效验
  20. 无锡中软国际有限公司笔试题(Java)

热门文章

  1. 4.1.9 OS之文件系统的层次结构
  2. Linux C :系统调用-fork,wait,subreaper
  3. 设置python编程环境_JupyterNotebook设置Python环境的方法步骤
  4. Cache相关基本概念理解
  5. Cpp 对象模型探索 / 成员初始化列表
  6. C/Cpp / 条件编译
  7. 启明云端分享| sigmastar ssd201_ffmpeg移植
  8. getValue()方法 java_java.util.zip.CRC32.getValue()方法示例
  9. 手把手教学电瓶车进电梯检测、多类别车辆追踪、异常行为检测产业级应用
  10. 0xbc指令 st75256_DDOS终极加速列车算法