函数防抖和节流

3,525 阅读3分钟

在网上,关于防抖和节流的实现方式已经很多了,这里也就不在依依列举,只是说说这两种思想方式,要注意,函数防抖和节流只是一种解决问题的设计思想罢了。

思想缘由

在浏览器中,频繁的操作 DOM 是非常消耗内存和 CPU 时间,在我们项目开发过程中,或多或少会绑定一些持续触发的事件,如 resize,scroll,mousemove 以及移动端 touchmove 等。同一个事件在同一刻产生大量的事件函数,若处理不当,轻则导致浏览器卡顿,重则导致浏览器崩溃,无论出现哪种情况,都不是我们所期望的,此时,函数防抖 (debounce) 和节流 (throttle) 的思想应运而生。

函数防抖和节流就是为了处理同一时刻事件的触发频率和事件函数的执行频率这两者关系的。 我们知道 DOM 事件的触发频率是不可控的,因此我们只能控制事件函数的执行频率,只要是没有达到条件要求的事件,都不触发事件函数,通过这一手段,可以极大的优化浏览器的性能。

函数防抖

函数防抖是指某事件被频繁的触发,在延迟一定的时间内,若该事件没有继续被触发,则执行事件函数,在整个过程中,事件函数只会被触发一次。

应用场景:在事件连续触发过程中,你期望事件函数只执行一次,例如:Ajax实时搜索(keydown)。

举个例子,我们在浏览页面内容的时候经常会使用到滚动条,若此时我们绑定了一个滚动条事件,但是,并没有加任何的防抖保护,这意味着用户只要触动了滚动条,就会产生成百上千条滚动事件,进而触发成百上千次事件函数,若每条事件函数的时间复杂度为O(n²),后果可想而知,直接把浏览器搞崩了,这样的产品,还没开始,已经结束了。

此时,若加上防抖,效果就大大的不同了,我们虽然无法阻止事件的触发频率,但是可以控制事件函数的执行频率,无论你触发了多少次事件,只要在保护时间内有触发,就不执行事件函数,反之,执行。

没有什么能比图片更形象的了👇

防抖

function debounce(func, wait) {
  let timeout = null;
  return function() {
    let _this = this;
    let args = arguments;
    if (timeout) {
      clearTimeout(timeout)
    }
    timeout = setTimeout(() => {
        func.apply(_this, args)
    ), wait)
  }
}

防抖的核心就是通过定时器来延迟事件函数的执行,在未达到定时器时间情况下,依旧产生了触发事件,就将上一个定时器删除。

函数节流

函数节流是指某事件被频繁的触发,在事件触发期间,它会周期的执行事件函数。

举个例子,水滴的下落,我们将水喉拨到一个角度,水滴会周期性一滴一滴的滴落。

应用场景:在事件连续触发过程中,你期望周期性的间隔一定时间来调用回调函数,例如:计算鼠标移动的距离(mousemove)

节流

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