语义化 防 抖 & 节 流 的区别

716 阅读3分钟

前言

  • 在日常的需求开发过程中,对节流和防抖这两个概念应该都不陌生。
  • 在处理高频的触发事件,比如:监听scroll、resize等事件以及提交按钮的处理上都会使用到。
  • 楼主以前对着两个概念的理解一直只是在于表面,平时也是直接引入lodash.js的 防抖debounce 和 节流throttle 使用就完事了

今天决定下点功夫来把这两个概念弄清楚,并自己实现这两个方法

防抖

从上一次被调用后,延迟 wait 毫秒后调用 func 方法 ---- 摘自Lodash.js

// 自己实现
const debounce = function (func, delay) {
    let pig = null
    return function () {
        if (pig) clearTimeout(pig)
        pig = null
        let self = this
        let args = arguments.slice(0)
        pig = setTimeout(() => {
            func.apply(self, args)
        }, delay)
    }
}

节流

在 wait 秒内最多执行 func 一次的函数 ---- 摘自Lodash.js

// 自己实现
const throttle = function (func, delay) {
    let timer = null
    return function () {
        let self = this
        let args = arguments.slice(0)
        if (!timer) {
            timer = setTimeout(() => {
                func.apply(self, args)
                clearTimeout(timer)
                timer = null
            }, delay)
        }
    }
}

之所以使用闭包传递函数的参数,是因为:

由setTimeout()调用的代码运行在与所在函数完全分离的执行环境上。这会导致,这些代码中包含的 this 关键字在非严格模式会指向 window (或全局)对象,严格模式下为 undefined,这和所期望的this的值是不一样的 ----摘自MDN

区别

  1. 代码上:清除定时器的时机不同
  • 对比两段代码,可以看到代码的区别在于:使用clearTimeout的清除定时器的时机不同。我们可以把上一次的计时器比作前浪,当前的定时器比作后浪。防抖在每一次调用函数的时候,都会对上一个定时器进行清除,也就是所谓的后浪推前浪,最后只剩下了后浪
  • 而节流则是每一个计时器都是一个守卫,而清除定时器的方法可以比作40米大刀,每一个守卫在执行当前的方法的之后,才会拥有40米大刀。多次触发节流函数,就相当于当前有多个守卫进行排队,而触发的频率过大时,就相当于有其他的守卫进行插队,这时候40米大刀就会清除这些插队的守卫。因此达到每个守卫都好好排队的效果。
  1. 目的不同
  • 防抖的目的在于:控制在一段时间的内的多次冒泡事件,只触发一次
  • 节流的目的在于:控制在一段时间的内的多次冒泡事件,在一定的频率上进行触发

思考:

  • 防抖和节流都能达到减少高频率触发的问题。
  • 了解了两者之间的区别和实现原理后,在什么样的业务场景上使用什么样的方法,会更加的得心应手

最后,好好学习不会差,大家一起进步!