快捷搜索:

JS面试题---防抖和节流

一、防抖

问题场景:有时会遇到这样一个情况,比如在一个搜索框里面进行搜索,在没有进行函数防抖的情况下,当我们在输入框中修改里面的值,我们想要的是等我们输入完成后再执行对输入关键字的搜索,这里就开始出现问题,如下面的例子。

<!DOCTYPE html>
<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>Document</title>
  <script>
    window.onload = function() {
            
     
      // 模拟ajax请求,传入的是待搜索的内容
      let count = 0;
      function ajax(params) {
            
     
        console.log(这是第+(++count)+次请求,内容是:+params);
      }
      // 绑定输入框
      let search = document.getElementById(serach);
      search.onkeyup = function(e) {
            
     
        //调用ajax
        ajax(e.target.value)
      }

    }
  </script>
</head>
<body>
  <div>
    <span>请输入搜索内容</span>
    <input id="serach" type="text">
  </div>
</body>
</html>

可以看到由于我们短时间触发了多次事件,导致不停的调用ajax,可是最后一次请求才是我们需要的,这叫造成了资源的浪费,因此我们必须通过防抖函数来杜绝这个现象。

原理概念:在事件被触发n秒后再执行回调,如果在这n秒内又被触发,则重新计时。

代码实现:

<script>
    window.onload = function() {
          
   
      // 模拟ajax请求,传入的是待搜索的内容
      let count = 0;
      function ajax(params) {
          
   
        console.log(这是第+(++count)+次请求,内容是:+params);
      }

       // func是用户执行的功能,wait是等待时间
       const debounce = (func,wait = 100) => {
          
   
        // 缓存一个定时器
        let timer = 0;
        // 返回的函数是每次调用的防抖函数
        return function(...args) {
          
   
          // 如果已经开启过定时器,那么这里就是清空上一次的定时器
          if(timer) {
          
   
            clearTimeout(timer);
          }
          // 如果没有,则定义一个新的定时器,延长用户传入的方法
          timer = setTimeout(() => {
          
   
            func.apply(this,args);
          },wait)
        }
      }

      // 绑定输入框
      let search = document.getElementById(serach);
      // 给ajax绑定防抖函数
      let debounceA = debounce(ajax,1000);
      search.onkeyup = function(e) {
          
   
        // 在有防抖函数下调用ajax
        // ajax(e.target.value)
        debounceA(e.target.value)
      }
      
    }
  </script>

可以看到,因为我传入的等待时间是1s,所以只有当输入停下来,并且超过一秒没有触发键盘时间才会发送请求。到这里,防抖的功能也就实现了。(在按钮提交,为了防止多次按钮提交,表单验证都可以使用到防抖函数)

二、节流

问题场景:我们平常在百度时,比如要搜索一个人的信息— 卢·猫之守护者·哮喘症征服者·被光选中的人·迪,讲道理这么长的名字很可能记不住 ,但是防抖函数又会延迟搜索,如果这个时间很大(3s),本来用户输入 卢·猫就能准确的找到,但是只有等3s后才能给出信息,就会非常影响用户的体验,可能有小伙伴会想,我直接在防抖函数把延迟执行的值改小一点不就行了吗?这样做是可以,但是会造成该防抖函数的适用性小,非常不灵活,所以需要另一种方法—节流。

原理概念:规定在一个单位时间内,只能触发一次函数。如果这个函数时间触发多次函数,只有一次有效。和防抖函数差不多。

代码实现:

<script>
    window.onload = function() {
          
   
      // 模拟ajax请求,传入的是待搜索的内容
      let count = 0;
      function ajax(params) {
          
   
        console.log(这是第+(++count)+次请求,内容是:+params+ +new Date().getSeconds());
      }

       // func是用户执行的功能,wait是等待时间
       const throttle  = (func,wait = 100) => {
          
   
        // 上一次执行函数的时间
        let lastTime = 0;
        // 返回的函数是每次调用的防抖函数
        return function(...args) {
          
   
          // 当前时间
          let now = +new Date();
          // 如果当前时间和上一次执行时间的差值大于等待时间,则执行函数
          if(now - lastTime > wait) {
          
   
            lastTime = now;
            func.apply(this,args);
          }
        }
      }
   
      // 绑定输入框
      let search = document.getElementById(serach);
      // 给ajax绑定防抖函数
      let throttleA = throttle(ajax,1000);
      search.onkeyup = function(e) {
          
   
        // 在有节流函数下调用ajax
        // ajax(e.target.value)
        throttleA(e.target.value)
      }
      
    }
  </script>

可以看到,节流函数设置的延迟时间是1s,不论我们在这1s内触发多少次键盘事件,ajax请求只会执行一次。(在图片的拖拽中,不用节流会造成卡顿,使用节流会流畅许多)

经验分享 程序员 职场和发展