防抖

190 阅读2分钟

防抖 : 在规定时间内触发,规定时间会从新计时,直到最后一次触发,规定时间后才会触发。 参考: 游戏技能释放需要蓄力,每次点击技能都会从新蓄力,只有蓄力满了才能释放技能。

防抖:限制函数执行的频次,避免函数触发频率过高而引发 延迟, 卡顿等现象。

用法如下:

<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <title>Title</title>
</head>
<body>
 <button id="myBtn" onclick="btnAction()" >点击 </button>
</body>
<script>
  // 事件
   const task = (name) => {
      console.log('commit message!!!',name)
    }

   const debounceTask = debounce(task, 3000)
   
    function debounce(fn, delay) {
        let timer
        //这里return的是一个函数,需要在事件绑定中再次调用。
        return function (...args) {
          // 清处时间
          if (timer) clearTimeout(timer)
          //这里在第一次点击时会等延迟完后才会执行。
          timer = setTimeout(() => {
            fn.apply(this, args)
          }, delay)
        }
      }


   const debounceTask = debounce(task, 3000)
   function btnAction(){ 
    debounceTask(11111)
   }
  //  document.getElementById("myBtn").addEventListener("click", debounceTask);


</script>
</html>

第一种:事件触发,需要等延迟时间结束后才会执行。

function debounce(fn, delay) {
    let timer
    return function (...args) {
      // 清处时间
      if (timer) {
        clearTimeout(timer)
      }
      timer = setTimeout(() => {
        fn.apply(this, args)
      }, delay)
    }
  }

第二种:事件触发,立即执行

function debounce(fn, delay) {
    let timer
    return function (...args) {
        // 清处时间
        if (timer) {
            clearTimeout(timer)
        }
    //  这里的timer在第一次执行时,只是在上面声明了,没有赋值所以是undifiend,而undifiend 取反是true,所以第一次点击时会立即执行。 而后面的点击timer会被定时器附上时间id,值类型是数字 再取反是false,所以第二次之后就不回走这个if语句了 。
        if (!timer) {
            console.log(' right now!!!');
            fn.apply(this.args)
        }
        timer = setTimeout(() => {
            fn.apply(this, args)
        }, delay)
    }
}

第三种:根据参数来判断

function debounce(fn, wait, immediate) {
    // timer用来记录当前函数执行状态
    let timer = null

    return function () {
        // 利用this和arguments获取作用域和变量
        let args = arguments
        let context = this
        //  这里的timer在第一次执行时,只是在上面声明了,没有赋值所以是undifiend,而undifiend取反是true,所以第一次点击时会立即执行。 而后面的点击timer会被定时器附上时间id,值类型是数字 再取反是false,所以第二次之后就不回走这个if语句了 。
        if (immediate && !timer) {
            fn.apply(context, args)
        }
        // 清理掉正在执行的函数并重新执行
        if (timer) clearTimeout(timer)
        timer = setTimeout(() => {
            fn.apply(context, args)
        }, wait)
    }
}