JS性能优化之防抖函数

284 阅读1分钟

「这是我参与11月更文挑战的第13天,活动详情查看:2021最后一次更文挑战

前言

函数的防抖节流,目前我们前端很多项目都运行在浏览器下,那就有很多的人机交互的操作,那我们对按钮可以有很高频率的事件点击,那这样对浏览器有一定的性能消耗的

场景

  • 滚动事件
  • 输入的模糊匹配
  • 轮播图切换
  • 点击操作
  • ...

浏览器默认情况下都会有总结的监听事件间隔(谷歌:4-6ms),如果监测到多次事件的监听执行,那么就会造成不必要的资源浪费

防抖

对于高频的操作来说,我们只希望识别一次点击,可以任务是第一次或者是最后一次

函数实现

/**
* handle 执行函数
* wait 事件触发之后多久开始执行
* immeadite 控制是第一次执行还是最后一次执行
*/
const obj = {
        wait: 300,
        immeadite: false
    }
function myDebounce (handle, obj = obj) {
    if(typeof handle !== 'function') {
       throw new Error('必须传入方法')
    }
    if(!obj instanceof Object) {
        throw new Error('请传入合适的参数')
    }
    let timer = null
    return function proxy (...args) {
       let self = this
       let init = obj.immeadite && !timer
       clearTimeout(timer)
       timer = setTimeout(() =>{
             timer = null
            !obj.immeadite && handle.apply(self, args)
        }, obj.wait)
        // 如果当前传递进来的值 是 true, 那么就表示我们需要立即执行这个函数
        // 如果需要实现在第一次执行,那么添加上 timer 为 null作为判断
        // 因为只要 timer为 null 就以意味着没有第二次点击
        init && handle.apply(self, args)
    }
}

这里送上我的测试用代码:

<!DOCTYPE HTML>
<html>

<head>
  <meta http-equiv="Content-Type"
        content="text/html; charset=utf-8">
  <title>事件</title>
</head>

<body>
  <button id="btn">计算</button>
  <script>
    var Btn = document.getElementById('btn');
    const obj = {
      wait: 300,
      immeadite: false
    }
    function myDebounce(handle, obj = obj) {
      if (typeof handle !== 'function') {
        throw new Error('必须传入方法')
      }
      let isObject = Object.prototype.toString.call(obj) ==='[object Object]'
      if (!isObject) {
        throw new Error('请传入合适的参数')
      }
      let timer = null
      return function proxy(...args) {
        let self = this
        let init = obj.immeadite && !timer
        clearTimeout(timer)
        timer = setTimeout(() => {
          timer = null
          !obj.immeadite && handle.apply(self, args)
        }, obj.wait)
        // 如果当前传递进来的值 是 true, 那么就表示我们需要立即执行这个函数
        // 如果需要实现在第一次执行,那么添加上 timer 为 null作为判断
        // 因为只要 timer为 null 就以意味着没有第二次点击
        init && handle.apply(self, args)
      }
    }
    function btnclick (a) {
      console.log("push the button",a);
    }
    Btn.onclick = myDebounce(btnclick, {
      wait: 3000,
      immeadite: false
    })
  </script>
</body>

</html>