JavaScript | 手写节流、防抖(面试篇)

279 阅读1分钟

持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第21天,点击查看活动详情

一、前言

函数的节流(throttle)与防抖(debounce)都是为了节约函数性能的一种优化方案

二、节流

1. 概念

节流(throttle):让函数在单位时间内只调用一次,第一次调用生效,比如发送验证码(每隔一段时间)就比如游戏里的技能cd。

2. 对比使用节流前后

我们拿鼠标的移动事件举个例子

节流前

鼠标移动就会不停触发 动画.gif

<body>
    <div class="box"></div>
</body>

<script>
     var oBox = document.querySelector('.box')
       var lastTime = 0
       oBox.onmousemove = function(){
        var nowTime = Date.now()
        console.log(nowTime-lastTime)
        lastTime = nowTime
       }
</script>
 
 <style>
   .box{
        width: 200px;
        height: 200px;
        background-color: pink;
        margin: 200px auto;
    }
  </style>

节流后

不管鼠标事件出发多少次,时间限制每隔500毫秒触发一次 动画.gif

<body>
    <div class="box"></div>
</body>

<script>
      //我们是无法改变鼠标的移动事件的触发,只是让代码执行频率变少
     var oBox = document.querySelector('.box')
       var lastTime = 0
       oBox.onmousemove = function(){
        var nowTime = Date.now()
        reduce = nowTime-lastTime
        if(reduce<=500){return}
        lastTime = nowTime
        console.log(1)
       }
</script>
 
 <style>
   .box{
        width: 200px;
        height: 200px;
        background-color: pink;
        margin: 200px auto;
    }
  </style>

3. 手写节流

<body>
    <div class="box"></div>
</body>
<script>
   //封装一个节流函数
   function throttle(fn,time){
       //绑定事件的时候,先初始化一个上一次的事件
       var lastTime = 0
       //这个函数是事件触发的时候真正调用的事件函数
       return function(){
         var nowTime = Date.now()
         //相当于一个节流阀,只有满足才会真正的调用传进来的函数
         if (nowTime - lastTime < time) {
                return;
            }
          lastTime = nowTime;
          /**
           1.要考虑传进来的函数event问题:arguments
            arguments所在的函数就是真正的事件函数,拥有实参event
            把event事件对象传递给fn,传进来的函数(move)就可以使用event对象了
           2.要考虑传进来函数的this指向问题:call(this)
          **/
          fn.call(this, arguments[0])
       }
  }
  //节流后需要被调用的逻辑代码函数
  function move(){
   console.log(1)
   console.log(event)
   console.log(this)
  }
  var oBox = document.querySelector('.box')
  //移动鼠标调用封装的节流函数
  oBox.onmousemove = throttle(move,2000)
  
  //滚动节流之后真正需要调用的函数
  function scroll(){
    console.log('滚了')
  }
  //滚动事件
  window.onscroll = throttle(scroll,1000)
  </script>

<style>
body{height:3000px}
.box{
    width: 200px;
    height: 200px;
    background-color: pink;
    margin: 200px auto;
}
</style>

最后验证

动画.gif

三、防抖

  1. 概念:防抖(debounce):让函数在单位时间内只调用一次,最后一次生效,比如搜索框,就比如游戏里最后一次回城被打断之前。
  2. 手写防抖
 <body>
      <input type="text" id="ipt">
 </body>
 
 <script>
//封装一个防抖函数
function debounce(fn,time){
  var timer = null;
  //事件函数
  return function(){
    //每次触发的时候,先把上一次的计时器清掉,然后重新开始计时
    clearTimeout(timer)
    //在计时器中 arguments是不符合的,要使用这个位置的arguments,先保存起来
    var arg = arguments;
     //保存外边的this 在计时器函数中使用
   var that = this;
    //每次触发事件,先不执行,要延迟一定的事件再执行
     timer = setTimeout(function () {
             fn.call(that, arg[0]);
      }, time)
 }
}
 //逻辑函数
function inputChange(e) {
    console.log("表单改变 请求数据");
    console.log(e);
    console.log(this);
}
var oIpt = document.querySelector('#ipt')
//调用防抖函数
 oIpt.oninput = debounce(inputChange, 800)
       
 </script>

验证结果

只在最后一次输入之后才调用

动画.gif

好了,以上就是本篇文章的分享,感谢阅读!