防抖和节流

116 阅读2分钟

防抖

所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数 执行时间。 ps: 重置普攻

策略

当事件被触发时,设定一个周期延时执行动作,若周期又被触发,则重新设定周期,直到周期结束,执行动作。 在后期有拓展了前缘防抖函数,即执行动作在前,设定延迟周期在后,周期内有事件被触发,不执行动作,且周期 重新设定。

防抖应用

用到防抖的地方还有很多很多,比如:搜索,当我们绑定input事件后,value每改变一次就会触发这个事件向后台请求内容,而用户此时需要搜索的内容还没写完,可我们就已经发送了很多次请求了,正确的做法是利用防抖,当用户最后一次输入后一段时间内不再输入就判定输入完成,再向后台发送请求。

再比如分页、文本编辑器实时保存(当无任何更改操作一秒后进行保存)、DOM 元素的拖拽功能实现、计算鼠标移动的距离等等。

防抖案例

<!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>
  </head>
 <body>
    <input type="text" />
    <script>
      const inp = document.querySelector("input");
      inp.oninput =  debounce(sayDebounce)
     
      function debounce(fn, interval) {
        let timer = null; // 定时器
        return function () {
         // 清除上一次的定时器
          clearTimeout(timer);
          // // 拿到当前的函数作用域 因为用了箭头函数下边 所以不需要这个了
          // let _this = this;
        
          // 拿到当前函数的参数数组
          // let args = Array.prototype.slice.call(arguments, 0);
         
          // 开启倒计时定时器
          timer = setTimeout (()=> {

            // 通过apply传递当前函数this,以及参数 apply特性
            fn.apply(this, [...arguments]);

            // 默认300ms执行
          }, interval || 300);
        };
      }

      function sayDebounce(a) {
      // ... 有些需要防抖的工作,在这里执行
      console.log("防抖成功!");
      console.log(a.target)
    }

    </script>

  </body>

</html>

节流

所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。 节流会稀释函数的执行频率。

对于节流,有多种方式可以实现 时间戳 定时器 束流等。

ps : 技能CD :

策略

固定周期内,只执行一次动作,若没有新事件触发,不执行。周期结束后,又有事件触发,开始新的周期。

特点:

连续高频触发事件时,动作会被定期执行,响应平滑

节流案例

<button id="debounce">点我防抖!</button>
    <script>

      // 1、获取这个按钮,并绑定事件
      var myDebounce = document.getElementById("debounce");
      // myDebounce.addEventListener("click", debounce(sayDebounce));
      myDebounce.onclick = throttle(sayDebounce);


      function throttle(fn, interval) {
        let timer = null; // 定时器
        let firstTime = true; // 判断是否是第一次执行
        
        // 利用闭包
        return function () {

          // 拿到函数的参数数组

          let args = Array.prototype.slice.call(arguments, 0);

          // 拿到当前的函数作用域

          let _this = this;

          // 如果是第一次执行的话,需要立即执行该函数

          if (firstTime) {

            // 通过apply,绑定当前函数的作用域以及传递参数

            fn.apply(_this, args);

            // 修改标识为null,释放内存

            firstTime = null;

          }

          // 如果当前有正在等待执行的函数则直接返回

          if (timer) return;

          // 开启一个倒计时定时器

          timer = setTimeout(function () {

            // 通过apply,绑定当前函数的作用域以及传递参数

            fn.apply(_this, args);

            // 清除之前的定时器

            timer = null;

            // 默认300ms执行一次

          }, interval || 3000);

        };

      }


      // 3、需要进行防抖的事件处理

      function sayDebounce(a) {

        // ... 有些需要防抖的工作,在这里执行

        console.log(111);

        console.log(a.target);

      }

function throttle(fn,wait) {
    let timer;
    return function() {
        let args = arguments;
        if(!timer) {
            timer = setTimeout(()=>{
                timer = null;
                fn.apply(this,args);
            },wait)
        }
    }
}