魔乐社区 如何防止重复发送ajax请求

如何防止重复发送ajax请求

  先来说说重复发送ajax请求带来的问题 - 场景一:用户快速点击按钮,多次相同的请求打到服务器,给服务器造成压力。如果碰到提交表单操作,而且恰好后端没有做兼容处理,那么可能会造成数据库中插入两条及以上的相同数据 - 场景二:用户频繁切换下拉筛选条件,第一次筛选数据量较多,花费的时间较长,第二次筛选数据量较少,请求后发先...

yetaoseo  ·  2021-08-16 15:50:13 发布

  先来说说重复发送ajax请求带来的问题 - 场景一:用户快速点击按钮,多次相同的请求打到服务器,给服务器造成压力。如果碰到提交表单操作,而且恰好后端没有做兼容处理,那么可能会造成数据库中插入两条及以上的相同数据 - 场景二:用户频繁切换下拉筛选条件,第一次筛选数据量较多,花费的时间较长,第二次筛选数据量较少,请求后发先至,内容先显示在界面上。但是等到第一次的数据回来之后,就会覆盖掉第二次的显示的数据。筛选结果和查询条件不一致,用户体验很不好

  为了解决上述问题,通常会采用以下几种解决方案 - 状态变量

  发送ajax请求前,btnDisable置为true,禁止按钮点击,等到ajax请求结束解除限制,这是我们最常用的一种方案

  如何防止重复发送ajax请求_如何防止重复发送ajax请求如何防止重复发送ajax请求_如何防止重复发送ajax请求_02

  但该方案也存在以下弊端: - 与业务代码耦合度高 - 无法解决上述场景二存在的问题

  函数节流和函数防抖

  固定的一段时间内,只允许执行一次函数,如果有重复的函数调用,可以选择使用函数节流忽略后面的函数调用,以此来解决场景一存在的问题

  如何防止重复发送ajax请求_如何防止重复发送ajax请求_03如何防止重复发送ajax请求_如何防止重复发送ajax请求_04如何防止重复发送ajax请求_如何防止重复发送ajax请求_05如何防止重复发送ajax请求_如何防止重复发送ajax请求_06

  也可以选择使用函数防抖忽略前面的函数调用,以此来解决场景二存在的问题

  如何防止重复发送ajax请求_如何防止重复发送ajax请求_07如何防止重复发送ajax请求_如何防止重复发送ajax请求_08如何防止重复发送ajax请求_如何防止重复发送ajax请求_09如何防止重复发送ajax请求_如何防止重复发送ajax请求_10

  该方案能覆盖场景一和场景二,不过也存在一个大问题: - wait time是一个固定时间,而ajax请求的响应时间不固定,wait time设置小于ajax响应时间,两个ajax请求依旧会存在重叠部分,wait time设置大于ajax响应时间,影响用户体验。总之就是wait time的时间设定是个难题

  作为一个成熟的ajax应用,它应该能自己在pending过程中选择请求拦截和请求取消 - 请求拦截

  用一个数组存储目前处于pending状态的请求。发送请求前先判断这个api请求之前是否已经有还在pending的同类,即是否存在上述数组中,如果存在,则不发送请求,不存在就正常发送并且将该api添加到数组中。等请求完结后删除数组中的这个api。

  请求取消

  用一个数组存储目前处于pending状态的请求。发送请求时判断这个api请求之前是否已经有还在pending的同类,即是否存在上述数组中,如果存在,则找到数组中pending状态的请求并取消,不存在就将该api添加到数组中。然后发送请求,等请求完结后删除数组中的这个api

  接下来介绍一下本文的主角 的 (查看详情)。通过 的 ,我们可以轻松做到请求拦截和请求取消

  官网示例中,先定义了一个 ,定义可以在axios源码目录下找到

  示例中调用了的source方法,所以接下来我们再去目录下看看source方法

  source方法返回一个具有和属性的对象,这两个属性都和构造函数有关联,所以接下来我们再看看构造函数

  所以souce.token是一个CancelToken的实例,而source.cancel是一个函数,调用它会在CancelToken的实例上添加一个reason属性,并且将实例上的promise状态resolve掉

  官网另一个示例

  它与第一个示例的区别就在于每个请求都会创建一个CancelToken实例,从而它拥有多个cancel函数来执行取消操作

  我们执行axios.get,最后其实是执行axios实例上的request方法,方法定义在

  request方法返回一个链式调用的promise,等同于

  在阅读源码的过程中,这些编程小技巧都是非常值得学些的

  接下来看看中的方法

  如果是cancel方法立即执行,创建了CancelToken实例上的reason属性,那么就会抛出异常,从而被response拦截器中的rejected方法捕获,并不会发送请求,这个可以用来做请求拦截

  如果cancel方法延迟执行,那么我们接着去找中的defaults.adapter

  终于找到中的

  可以看到xhrAdapter创建了XMLHttpRequest对象,发送ajax请求,在这之后如果执行cancel函数将cancelToken.promise状态resolve掉,就会调用request.abort(),可以用来请求取消

  剩下要做的就是将cancelToken从业务代码中剥离出来。我们在项目中,大多都会对axios库再做一层封装来处理一些公共逻辑,最常见的就是在response拦截器里统一处理返回code。那么我们当然也可以将cancelToken的配置放在request拦截器。可参考demo

  每次执行request拦截器,判断pendingAjax数组中是否还存在同样的url。如果存在,则删除数组中的这个api并且执行数组中在pending的ajax请求的cancel函数进行请求取消,然后就正常发送第二次的ajax请求并且将该api添加到数组中。等请求完结后删除数组中的这个api

  每次执行request拦截器,判断pendingAjax数组中是否还存在同样的url。如果存在,则执行自身的cancel函数进行请求拦截,不重复发送请求,不存在就正常发送并且将该api添加到数组中。等请求完结后删除数组中的这个api

  是基于 的封装,针对 ,也有类似的解决方案 查看详情。大家可以针对各自的项目进行选取

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐

  • 浏览量 788
  • 收藏 0
  • 0

所有评论(0)

查看更多评论 
已为社区贡献58条内容