深刻理解js 防抖,节流技术


为什么防抖和节流?

我们使用窗口的 resize,scorll,mousemove,mousehover;输入框等校验时,如果事件处理函数调用无限制,会加剧浏览器的负担,尤其是执行了操作 DOM 的函数,那不仅造成计算资源的浪费,还会降低程序运行速度,甚至造成浏览的奔溃,影响用户体验。


防抖和节流有什么区别?

  • 防抖:就是触发多次事件,最后一次执行事件处理函数。在事件被触发后,等待一段时间(例如100毫秒),如果在这段时间内没有再次触发事件,才执行相应的操作。如果在等待时间内又触发了事件,则重新计时等待时间。

  • 节流:隔一段时间执行一次事件处理函数。在一定时间间隔内(例如每200毫秒),只允许事件执行一次。如果在这段时间内再次触发事件,忽略该事件,直到时间间隔过去,才允许下一次事件执行


防抖和节流有什么具体应用场景?

  • 防抖:适用于那些在短时间内频繁触发事件的情况,比如输入框输入事件窗口调整事件。防抖可以避免在用户还在输入过程中就立即执行操作,而是等待用户停止输入一段时间后再执行操作,减少频繁的操作执行。

  • 节流:适用于那些需要限制事件触发频率的情况,比如滚动事件鼠标移动事件、浏览器滚动监听事件。通过节流,可以确保在一定时间内只执行一次事件处理函数,避免过多的计算和操作。


防抖例子:

//  防抖函数
      let deBounce = (fn, delay) => {
        let timer = null
        return function(...args) {
          if (timer) clearTimeout(timer)
          timer = setTimeout(() => {
            fn(...args)
          }, delay)
        }
      }
      let oInput = document.getElementsByTagName('input')[0]
      //  模拟请求
      let ajax = message => {
        let json = { message }
        console.log(JSON.stringify(json))
      }
      let doAjax = deBounce(ajax, 200)

      // 键盘弹起执行
      oInput.addEventListener('keyup', e => {
        doAjax(e.target.value)
      })


节流例子:

/*
     * 连续点击只会1000执行一次btnClick函数
     */
    let obutton = document.getElementsByTagName('button')[0]
    //  如果用箭头函数,箭头函数没有arguments,也不能通过apply改变this指向
    function btnClick() {
      console.log('我响应了')
    }
    /*
            方法1: 定时器方式实现
            缺点:第一次触发事件不会立即执行fn,需要等delay间隔过后才会执行
         */
    let throttle = (fn, delay) => {
      let flag = false
      return function(...args) {
        if (flag) return
        flag = true
        setTimeout(() => {
          fn(...args)
          flag = false
        }, delay)
      }
    }
    /*
            方法2:时间戳方式实现
            缺点:最后一次触发回调与前一次的触发回调的时间差小于delay,则最后一次触发事件不会执行回调
          */
    let throttle = (fn, delay) => {
      let _start = Date.now()
      return function(...args) {
        let _now = Date.now(),
          that = this
        if (_now - _start > delay) {
          fn.apply(that, args)
          start = Date.now()
        }
      }
    }

    // 方法3:时间戳与定时器结合
    let throttle = (fn, delay) => {
      let _start = Date.now()
      return function(...args) {
        let _now = Date.now(),
          that = this,
          remainTime = delay - (_now - _start)
        if (remainTime <= 0) {
          fn.apply(that, args)
        } else {
          setTimeout(() => {
            fn.apply(that, args)
          }, remainTime)
        }
      }
    }
    /*
         方法4:requestAnimationFrame实现
         优点:由系统决定回调函数的执行机制,60Hz的刷新频率,每次刷新都会执行一次回调函数,不
         会引起丢帧和卡顿
         缺点:1.有兼容性问题2.时间间隔有系统决定
        */
    let throttle = (fn, delay) => {
      let flag      return function(...args) {
        if (!flag) {
          requestAnimationFrame(function() {
            fn.apply(that, args)
            flag = false
          })
        }
        flag = true
      }
    }

    obutton.onclick = throttle(btnClick, 1000)


声明:BenBonBen博客|版权所有,违者必究|如未注明,均为原创

转载:转载请注明原文链接 - 深刻理解js 防抖,节流技术


过去太迟,未来太远,当下最好