一。在进行前端开发过程中,经常会遇到需要请求同一个数据接口但不同参数的需求,这种情况下当用户通过页面操作频繁请求该接口,而接口的不同参数响应时间差异较大时,容易引发数据渲染混乱的bug。
举例说明:假设页面上有button1,button2两个按钮,点击这两个按钮会请求同一个后台接口,但发送的参数不同,由于参数的不同后台操作数据库的查询语句会有一定差异,这就导致了不同的查询操作耗时可能差异巨大。再假设button1发送的参数响应的时间为2秒,button2发送的参数响应时间为1秒,用户快速先后点击了button1和button2按钮。这时会先后发送两个ajax请求,过了1秒后button2的响应数据先返回渲染到DOM上,又过了1秒后button1的响应数据返回后渲染到DOM覆盖button2的数据。而这时用户页面button2由于是后点击的,处于选中状态,用户期望查看button2对应的数据,但是最后却展示button1按钮的数据,这与用户的期望不符合,是一个严重的bug。
二。下面我们分析一下导致此bug的原因:
   1.用户快速频繁的操作,导致了多次发送同一接口不同参数的请求。
   2.后台接口由于不同参数的查询操作导致数据响应时间差异大。
如果用户没有快速操作,两次请求发送的时间有一定间隔,这时即使接口响应时间略有差异,也不会出现上述bug。如果后台数据响应时间差异很小,即使用户快速操作也不会出现上述bug。正是由于以上1、2两个原因共同作用导致了bug的出现。
三。分析了bug产生的原因,我们有针对性的进行解决。

    方案一:限制用户快速进行同类操作,当用户通过操作触发了一次请求后,将同类的操作按钮禁用,成功响应数据后再将按钮解除禁用。示例代码如下:

   <template>
     <div>
      <button @click="sendReq" :disabled="isDisabled">button1</button>
      <button @click="sendReq" :disabled="isDisabled">button2</button>
      <p>{{content}}</p>
     </div>
   </template>
   <script>
     export default {
       data(){
         return {
           isDisabled : false,  //控制按钮可用性
           content : '' //响应数据内容
         }
       }
     }
     methods : {
       sendReq(){
         this.isDisabled = true; //禁用操作按钮
         this.$axios.get('/xxxx?id=1').then(response=>{
           this.isDisabled = false;
           this.content = response.content;
	 })
       }
     }
   </script>

   这种方案优点是简单粗暴,缺点是如果数据响应时间较长时,用户体验不好。
   方案二:分析用户行为会发现,用户快速操作同一接口后,只希望得到最后一次操作的数据。由此想到当用户快速操作同一接口时,只发送最后一次操作的ajax请求,即可在一定程度上解决该bug。这里我设置一个名为timer的500毫秒的一次性定时器,每次用户操作时首先清除没有执行timer定时器,然后通过timer定时器延迟500毫秒执行ajax请求,这样用户在500毫秒内执行的相同操作时,没执行的timer定时器被清理,始终只会保留最后一次操作的ajax请求,500毫秒内没有相同操作时,会发送该请求。代码如下:

<template>
 <div>
   <button @click="sendReq">button1</buttono>
   <button @click="sendReq">button2</button>
   <p>{{content}}</p>
 </div>
</template>
<script>
 export default {
  data(){
   return {
    timer : null, //定义定时器用
    content : '', //响应数据内容
   }
  }
 }
 methods : {
  sendReq(){
   clearTimerout(this.timer);  //清除没执行的timer定时器
   this.timer = setTimeout(()=>{ //定义一个timer定时器,延迟执行ajax请求
    this.$axios.get('/xxxx?id=1').then(response=>{
     this.content = response.content;
    })
   }, 500)
  }
 }
</script>

上述方案可以减少无用的ajax请求,节省性能;同时也可以在一定程度上解决上述bug,但并不能完全避免,该方案相当于设置了500毫秒的容差,可以解决后台数据响应时间差距在500毫秒以内产生的bug;当后台数据响应时间差距大与500毫秒时,仍然无法避免上述bug。在此基础上我们有了进一步的解决方案。方案为:做一个计时器,初始值为0,每一次发送ajax请求前为计时器做一个递加操作,发送ajax请求时将该值作为参数传给后台,接收响应数据时后台将该值再返回来,我们根据前端存储的计数器的值与后端返回来的值作比较,只有二者相等时说明返回的是最后一次用户操作的数据。如二者不相等,则返回的数据不是最后一次操作的数据。至此该bug完全解决。代码如下:

<template>
 <div>
  <button @click="sendReq">button1</button>
  <button @click="sendReq">button2</button>
  <p>{{content}}</p>
 </div>
</template>
<script>
 export defalut {
  data(){
   return {
    timer : null, //定义定时器
    counter : 0, //计时器
    content : '', //响应数据内容
   }
  }
 }
 methods : {
  clearTimerout(this.timer); //清除没执行的timer定时器
  this.counter++;
  this.timer = setTimeout(()=>{//定义一个timer定时器,延迟执行ajax请求
   this.$axios.get(`/xxxx?id=1&counter=${this.counter}`).then(resonse=>{
    if(response.counter < this.counter){ //后台返回的counter字段值与前端存储的计数器值做比较,如果不相等,这说明返回的数据不是用户最后一次操作的数据。因此不渲染数据到DOM上
      return;
    }
    this.content = response.content;
   })
  }, 500)
 }
</script>

 

Logo

前往低代码交流专区

更多推荐