人类高质量JS防抖与节流机制

一.速识防抖:

防抖与节流可谓是面试常见,其实很好理解,下面带你分分钟了解防抖与节流的基本思想与写法

在这之前,比如我们先定义一个按钮,并绑定一个点击事件,执行要触发的事件:

<!-- 定义一个按钮 -->
<input type="button" id="btn" value="按钮" />

<script>
// 获取标签
  var btn = document.getElementById("btn");
// 绑定事件  
  btn.addEventListener("click", real);
// 要触发的事件
  function real(e) {
    console.log("北极光之夜。");
    console.log(e);
  }
</script>  

执行如下:

在这里插入图片描述

可以发现,一直点击会一直触发事件,如果这个事件为发送一个请求,那么这对与服务器来说是很不友好的。同样的请求因为用户的多次点击而多次发送请求,返回的结果和只点击一次是一样的,大大加重服务器压力和影响性能。所以,我们引入防抖的概念,简单来说,防抖就是通过setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发。 直接看下面例子:

1.通过setTimeout的方式延迟执行:

第一种方式为通过设置setTimeout定时器的方式延迟执行,当快速多次点击的时候,每一次都会重置定时器,只有你一段时间都不点击时定时器才能到达条件并执行事件函数。

   <input type="button" id="btn" value="按钮" />
    <script>
      var btn = document.getElementById("btn");
      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
      btn.addEventListener("click", trigger(real, 1000));
      function trigger(fn, delay) {
        // 设置time为定时器,初始为 null
        var time = null;
         // 闭包原理,返回一个函数
        return function () {
          // 如果定时器存在清空定时器
          if (time) {
            clearTimeout(time);
          }
          // 设置定时器,规定时间后执行真实要执行的函数
          time = setTimeout(() => {
          // 将参数传递给真实执行的函数,因为箭头函数继承父级作用域,所以直接...arguments
            fn(...arguments);
          }, delay);
        };
      }
      //真实要执行函数
      function real(e) {
        console.log("北极光之夜。");
        console.log(e);
      }
    
   </script>  

其中会利用闭包的原理形成作用域,使得定时器不会被下一次点击重复或清空。
运行结果如下,每次点击都延迟执行。狂点时只有停下后才会执行:
在这里插入图片描述

2.通过setTimeout的方式第一次会执行,后面不执行:

可以发现,第一种方式虽然延迟执行了,但是当用户第一次点的时候也要延迟执行,那就很不友好了。所以下面改进,使得第一次点的时候立即执行,狂点的时候只有第一次有效后面的都没效:

   <input type="button" id="btn" value="按钮" />
    <script>
      var btn = document.getElementById("btn");
      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
      btn.addEventListener("click", trigger(real, 1000));
     function trigger(fn, delay) {
       // 设置time为定时器,初始为 null
        var time = null;
        return function () {
         //定义一个firstClick,判断是否第一次执行,初始值为true
          var firstClick = !time;
         //第一次会立即执行
          if (firstClick) {
            fn(...arguments);
          }
           // 如果定时器存在清空定时器
          if (time) {
            clearTimeout(time);
          }
           // 设置定时器,此时firstClick会变为false,规定时间后time才会为null
          time = setTimeout(() => {
            time = null;
          }, delay);
        };
      } 
      //真实要执行函数
      function real(e) {
        console.log("北极光之夜。");
        console.log(e);
      }
    
   </script>  

运行结果如下,第一次点的时候立即执行,狂点的时候只有第一次有效后面的都没效:
在这里插入图片描述

3.通过setTimeout的方式第一次会执行和最后一次执行:

前两个其实就是防抖的经典例子了。这里是扩展知识,继续改进上面案例使得只点击一次的时候立即执行。当点击多次时第一次和最后一次执行。

   <input type="button" id="btn" value="按钮" />
    <script>
      var btn = document.getElementById("btn");
      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为定时器延迟时间
      btn.addEventListener("click", trigger(real, 1000));
     function trigger(fn, delay) {
       // 设置time为定时器,初始为 null
        var time = null;
        return function () {
         //定义一个firstClick,判断是否第一次执行,初始值为true
          var firstClick = !time;
         //第一次会立即执行
          if (firstClick) {
            fn(...arguments);
          }
           // 如果定时器存在清空定时器
          if (time) {
            clearTimeout(time);
          }
           // 设置定时器,此时firstClick会变为false,规定时间后time才会为null
          time = setTimeout(() => {
            time = null;
            // 如果firstClick为true,执行
             if (!firstClick) {
              fn(...arguments);
            }
          }, delay);
        };
      } 
      //真实要执行函数
      function real(e) {
        console.log("北极光之夜。");
        console.log(e);
      }
    
   </script>  

运行结果如下,只点击一次的时候立即执行。当点击多次时第一次和最后一次执行。:
在这里插入图片描述

二.速识节流:

节流其实就很好理解了,减少一段时间的触发频率。简单来说,就是你一直狂点不停的话,它会每隔一定时间就执行一次。它与防抖最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。下面利用计算时间戳实现:

   <input type="button" id="btn" value="按钮" />
    <script>
      var btn = document.getElementById("btn");
      // 点击后触发trigger()函数,第一个参数为真实要执行的函数,第二个参数为限制时间
      btn.addEventListener("click", trigger(real, 500));
     function trigger(fn, delay) {
       // 设置bef,为上一次执行时间,初始为0
        var bef = 0;
        return function () {
        // 获取当前时间戳
          var now = new Date().getTime();
          //如果当前时间减去上次时间大于限制时间时才执行
          if (now - bef > delay) {
           // 执行函数
            fn(...arguments);
            //执行后,上次时间赋值为这次执行时间
            bef = now;
          }
        };
      }
      //真实要执行函数
      function real(e) {
        console.log("北极光之夜。");
        console.log(e);
      }
    
   </script>  

运行结果如下,一点就运行。狂点不停的话,每隔500毫秒才执行一次。:
在这里插入图片描述

也可以用定时器实现节流,如下:

实现第一次点的时候也延迟执行,狂点不停的话,它会每隔一定时间就执行一次。

 <input type="button" id="btn" value="按钮" />
    <script>
      var btn = document.getElementById("btn");
      btn.addEventListener("click", trigger(real, 500));
      function real(e) {
        console.log("北极光之夜。");
        console.log(e);
      }
      function trigger(fn, delay) {
      // flag为ture
        var flag = true;
        return function () {
         // 如果flag为true执行定时器
          if (flag) {
            setTimeout(() => {
              //到规定时间后执行函数,同时 flag = true;
              fn(...arguments);
              flag = true;
            }, delay);
          }
          // flag = false;防止一直执行
          flag = false;
        };
      }
</script>

效果如下:

在这里插入图片描述

三.总结:

防抖与节流方法多多,不同的需求也会有不同的写法,重要的是搞清原理就好。防抖就是通过setTimeout 的方式,在一定的时间间隔内,将多次触发变成一次触发 。节流:就是减少一段时间的触发频率。防抖与节流最大的区别就是,无论事件触发多么频繁,都可以保证在规定时间内可以执行一次执行函数。

在这里插入图片描述

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
JavaScript 中,防抖(debouncing)和节流(throttling)是两种优化高频率触发事件的方法,可以减少代码的执行次数,提高性能。 防抖 防抖是指在事件被频繁触发时,只有在一定时间内没有新的触发事件才会执行事件处理函数。在这段时间内,如果事件又被触发,则重新计时。 防抖的实现思路是:在事件处理函数执行前,设置一个定时器,如果在定时器时间内再次触发了事件,则清除原定时器并重新设置一个新的定时器,如此反复。如果在定时器时间内没有再次触发事件,则执行事件处理函数。 防抖的应用场景包括:搜索框输入、窗口调整等需要频繁触发事件时,可以通过防抖来减少事件处理函数的执行次数。 示例代码: ```javascript function debounce(func, delay) { let timer = null; return function () { const context = this; const args = arguments; clearTimeout(timer); timer = setTimeout(function () { func.apply(context, args); }, delay); }; } const searchInput = document.getElementById("search-input"); const searchHandler = function () { console.log("执行搜索操作"); }; searchInput.addEventListener("input", debounce(searchHandler, 500)); ``` 上面的代码中,`debounce` 函数接受一个事件处理函数和一个时间间隔作为参数,返回一个新的函数,这个新函数在被调用时会执行事件处理函数,但是在执行前会设置一个定时器,如果在时间间隔内再次被调用,则会清除原定时器并重新设置一个新的定时器。 节流 节流是指在事件被频繁触发时,只有在一定时间间隔内执行一次事件处理函数。在这段时间内,如果事件又被触发,则忽略这次触发。 节流的实现思路是:在事件处理函数执行前,判断距离上一次执行的时间间隔是否超过了指定的时间间隔,如果超过了,则执行事件处理函数并更新上一次执行时间;否则忽略这次事件触发。 节流的应用场景包括:页面滚动、DOM 元素拖拽等需要频繁触发事件时,可以通过节流来减少事件处理函数的执行次数。 示例代码: ```javascript function throttle(func, delay) { let lastTime = 0; return function () { const context = this; const args = arguments; const now = new Date().getTime(); if (now - lastTime >= delay) { func.apply(context, args); lastTime = now; } }; } const scrollHandler = function () { console.log("执行页面滚动操作"); }; window.addEventListener("scroll", throttle(scrollHandler, 500)); ``` 上面的代码中,`throttle` 函数接受一个事件处理函数和一个时间间隔作为参数,返回一个新的函数,这个新函数在被调用时会执行事件处理函数,但是在执行前会判断距离上一次执行的时间间隔是否超过了指定的时间间隔,如果超过了,则执行事件处理函数并更新上一次执行时间;否则忽略这次事件触发。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值