注册

vue阻止重复333请求(上)

背景

项目当中前端代码会遇到同一个请求向服务器发了多次的情况,我们要避免服务器资源浪费,同一个请求一定时间只允许发一次请求

思路

(1)如果业务简单,例如同一个按钮防止多次点击,我们可以用定时器做防抖处理
(2)如果业务复杂,例如多个组件通过代码,同一个请求发多次,这个时候防抖已经不好处理了,最好是对重复的ajax请求统一做取消操作

实现

方式1-通过定时器做防抖处理

(a)概述

效果:当用户连续点击多次同一个按钮,最后一次点击之后,过小段时间后才发起一次请求
原理:每次调用方法后都产生一个定时器,定时器结束以后再发请求,如果重复调用方法,就取消当前的定时器,创建新的定时器,等结束后再发请求,工作当中可以用第三方封装的工具函数例如lodashdebounce方法来简化防抖的代码

(b)代码


<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Documenttitle>
   <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js" type="application/javascript">script>
   <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript">script>
   <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript">script>
head>
<body>
   <div id="app">
       <button @click="onClick">请求button>
   div>
body>
<script>
// 定义请求接口
function sendPost(data){
   return axios({
       url'https://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test',
       method'post',
       data
  })
}
new Vue({
   el'#app',
   methods: {
       // 调用lodash的防抖方法debounce,实现连续点击按钮多次,0.3秒后调用1次接口
       onClick_.debounce(async function(){
           let res = await sendPost({username:'zs'age20})
           console.log('请求的结果'res.data)
      }, 300),
  },
})
script>
html>

(c)预览

连接

(d)存在的问题

无法解决多个按钮件的重复请求的发送问题,例如下面两种情况

情况-在点击事件上做防抖

按钮事件间是相互独立的,调用的是不同方法,做不到按钮间防抖效果


<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Documenttitle>
   <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js" type="application/javascript">script>
   <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript">script>
   <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript">script>
head>
<body>
   <div id="app">
       <button @click="onClick1" ref="btn1">请求1button>
       <button @click="onClick2" ref="btn2">请求2button>
   div>
body>
<script>
 
let sendPost = function(data){
   return axios({
       url'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test',
       method'post',
       data
  })
}
new Vue({
   el'#app',
   mounted() {
       this.$refs.btn1.click()
       this.$refs.btn2.click()
  },
   methods: {
       // 使用lodash对请求方法做防抖
       //这里有问题,只是对每个按钮的点击事件单独做了防抖,但是两个按钮之间做不到防抖的效果
       onClick1_.debounce(async function(){
           let res = await sendPost({username:'zs'age20})
           console.log('请求1的结果'res.data)
      }, 300),
       onClick2_.debounce(async function(){
           let res = await sendPost({username:'zs'age20})
           console.log('请求2的结果'res.data)
      }, 300),
  },
})
script>
html>

预览

情况2-在接口方法做防抖

按钮间调用的方法是相同的,是可以对方法做防抖处理,但是处理本身对方法做了一次封装,会影响到之前方法的返回值接收,需要对之前的方法做更多处理,变得更加复杂,不推荐


<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Documenttitle>
   <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/lodash.js/4.17.21/lodash.min.js" type="application/javascript">script>
   <script src="https://lf26-cdn-tos.bytecdntp.com/cdn/expire-1-M/vue/2.6.14/vue.min.js" type="application/javascript">script>
   <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript">script>
head>
<body>
   <div id="app">
       <button @click="onClick1" ref="btn1">请求1button>
       <button @click="onClick2" ref="btn2">请求2button>
   div>
body>
<script>
// 使用lodash对请求方法做防抖,    
let sendPost = _.debounce(function(data){
   //这里有问题,这里的返回值不能作为sendPost方法执行的返回值,因为debounce内部包裹了一层
   return axios({
       url'http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test',
       method'post',
       data
  })
}, 300)
new Vue({
   el'#app',
   mounted() {
       this.$refs.btn1.click()
       this.$refs.btn2.click()
  },
   methods: {
       onClick1async function(){
           //这里有问题,sendPost返回值不是promise,而是undefined
           let res = await sendPost({username:'zs'age20})
           console.log('请求1的结果'res)
      },
       onClick2async function(){
           let res = await sendPost({username:'zs'age20})
           console.log('请求2的结果'res)
      },
  },
})
script>
html>

预览

方式2-通过取消ajax请求

(a) 概述

直接对请求方法做处理,通过ajax库的api方法把重复的请求给取消掉

(b)原理

原生ajax取消请求

通过调用XMLHttpRequest对象实例的abort方法把请求给取消掉


<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Documenttitle>
head>
<body>
body>
<script>
//原生ajax的语法    
let xhr = new XMLHttpRequest();
xhr.open("GET""http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test?username=zs&age=20"true);
xhr.onload = function(){
   console.log(xhr.responseText)
}
xhr.send();
//在谷歌浏览器的低速3g下面测试
//通过XMLHttpRequest实例的abort方法取消请求
setTimeout(() => xhr.abort(), 100);
script>
html>

预览

axios取消请求

通过axiosCancelToken对象实例cancel方法把请求给取消掉


<html lang="en">
<head>
   <meta charset="UTF-8">
   <meta http-equiv="X-UA-Compatible" content="IE=edge">
   <meta name="viewport" content="width=device-width, initial-scale=1.0">
   <title>Documenttitle>
   <script src="https://lf9-cdn-tos.bytecdntp.com/cdn/expire-1-M/axios/0.26.0/axios.min.js" type="application/javascript">script>
head>
<body>
body>
<script>
/*axios的取消的语法*/
// 方式1-通过axios.CancelToken.source产生cancelToken和cancel方法
/*
const source = axios.CancelToken.source();
axios.get('http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', {
  params: {username: 'zs', age: 20},
  cancelToken: source.token
}).then(res=>{
  console.log('res', res.data)
}).catch(err=>{
  console.log('err', err)
})
//在谷歌浏览器的低速3g下面测试
//通过调用source的cancel方法取消
setTimeout(() => source.cancel(), 100);
*/

/**/
// 方式2-通过new axios.CancelToken产生cancelToken和cancel方法
let cancelFn
const cancelToken =  new axios.CancelToken(cancel=>{
   cancelFn = cancel
});
axios.get('http://nodejs-cloud-studio-demo-bkzxs.nodejs-cloud-studio-demo.50185620.cn-hangzhou.fc.devsapp.net/test', {
   params: {username: 'zs'age: 20},
   cancelToken: cancelToken
}).then(res=>{
   console.log('res'res.data)
}).catch(err=>{
   console.log('err'err)
})
//在谷歌浏览器的低速3g下面测试
//通过调用cancelFn方法取消
setTimeout(() => cancelFn(), 100);

script>
html>

预览

续:vue阻止重复请求(下)

作者:黄金林
来源:juejin.cn/post/7189231050806001719

0 个评论

要回复文章请先登录注册