作者:舒丽琦|奇舞团前端开发工程师
https://75.team/

在我们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) returnconst 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) returnconst 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);// 将当前请求添加到pendingAjaxthis.addPendingAjax(config);// ...
});

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

// 拦截响应
this.axios.interceptors.response.use(response => {removePending(response)return response
}, error => {// ...
})

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

(err) => {
// 类型是否为重复请求
let isDuplicatedType;
try {const errorType = (JSON.parse(error.message) || {}).typeisDuplicatedType = 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)

亲,点这涨工资 

如何优雅的解决”重复请求“问题相关推荐

  1. 接口如何优雅地处理重复请求

    接口如何优雅地处理重复请求 利用唯一请求编号去重 业务参数去重 请求去重工具类,Java实现 总结 对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的 ...

  2. 优雅地处理重复请求(并发请求)——附Java实现

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料! 来源:jaskey.github.io/blog/2020 ...

  3. 优雅地处理重复请求(并发请求)

    文章来源:https://sourl.cn/9ukjTx 目录 利用唯一请求编号去重 业务参数去重 计算请求参数的摘要作为参数标识 继续优化,考虑剔除部分时间因子 请求去重工具类,Java实现 总结 ...

  4. md5会重复吗_如何优雅地处理重复请求(并发请求)

    点击上方"服务端思维",选择"设为星标" 回复"669"获取独家整理的精选资料集 回复"加群"加入全国服务端高端社群「后 ...

  5. 设置公共请求参数_基于分布式锁的防止重复请求解决方案(值得收藏)

    关于重复请求,指的是我们服务端接收到很短的时间内的多个相同内容的重复请求.而这样的重复请求如果是幂等的(每次请求的结果都相同,如查询请求),那其实对于我们没有什么影响,但如果是非幂等的(每次请求都会对 ...

  6. 解决axios请求超时

    简介 在vue中经常使用axios发起网络请求,与服务器进行数据交互.在使用过程中会有许多问题存在,比如由于网络不稳定导致请求超时/失败,通常有两种解决方案,一种是提示用户重新提交请求,另一种是进行相 ...

  7. 想避免重复请求/并发请求?这样处理才足够优雅

    点击上方蓝色"方志朋",选择"设为星标" 回复"666"获取独家整理的学习资料!对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类 ...

  8. 如何优雅处理重复请求/并发请求?

    前言 一些用户请求在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些涉及写入操作,一旦重复了,可能会导致很严重的后果.例如交易接口如果重复请求,可能会重复下单. 重复的场景有可能是: ...

  9. 如何避免重复请求/并发请求?这样处理才足够优雅

    对于一些用户请求,在某些情况下是可能重复发送的,如果是查询类操作并无大碍,但其中有些是涉及写入操作的,一旦重复了,可能会导致很严重的后果,例如交易的接口如果重复请求可能会重复下单. 重复的场景有可能是 ...

最新文章

  1. 30005 rust_Steam三连冠老游戏《腐蚀(RUST)》为什么突然火起来了?
  2. .net core 程序退出事件
  3. responsebody如何将数据转换成json的_干货分享:如何用Retrofit直接获得Json数据(字符串)...
  4. red hat 5 和 oracle
  5. webui框架的利与弊
  6. Spring Cloud构建微服务架构(七)消息总线
  7. 坎宁安法则又称“卑鄙的人”
  8. 7-2 日期问题面向对象设计(聚合一) (35 分)
  9. PostgreSQL 10.1 手册_部分 II. SQL 语言_第 12 章 全文搜索_12.4. 额外特性
  10. 学习sql注入:猜测数据库_学习SQL:SQL数据类型
  11. JavaScript深入之执行上下文栈 1
  12. Javascript特效:利用封装动画函数模拟关闭安全管家弹窗
  13. HDFS的命令行使用【常用 hdfs 命令】
  14. 计算机绘图 cad),CAD计算机绘图入门
  15. 六、假设检验:使用Python进行两个正态总体均值的假设检验
  16. python 将图片中的颜色进行替换
  17. Rosalind Java| Counting Point Mutations
  18. java项目如何判断一个请求是否为AJAX请求
  19. 小程序服务器如何防攻击,中小网站防止DDOS攻击的方法
  20. java swing 字体显示_如何在Java Swing中使用Wingdings字体

热门文章

  1. 设备调试---用万用表寻找GND、RXD、TXD
  2. Neat Video Pro插件如何在Flame 2020中使用
  3. Hexo-neat插件优化提升访问效率
  4. 基于ssm的高校二手物品交易网 java idea mysql
  5. 自行车(山地车)拆脚踏
  6. 在进行USB CDC类开发时,无法发送64整数倍的数据(续)
  7. ssl证书购买后的认证签发过程
  8. 西安前端开发工程师待遇|哎呦不错呦
  9. [zz] 关于字体和字体微调(Hinting )的知识
  10. 应届年薪80万!这些程序员活得实在太太太爽了!