前言
- 在日常的需求开发过程中,对节流和防抖这两个概念应该都不陌生。
- 在处理高频的触发事件,比如:监听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
区别
- 代码上:清除定时器的时机不同
- 对比两段代码,可以看到代码的区别在于:使用clearTimeout的清除定时器的时机不同。我们可以把上一次的计时器比作前浪,当前的定时器比作后浪。防抖在每一次调用函数的时候,都会对上一个定时器进行清除,也就是所谓的
后浪推前浪,最后只剩下了后浪。 - 而节流则是每一个计时器都是一个
守卫,而清除定时器的方法可以比作40米大刀,每一个守卫在执行当前的方法的之后,才会拥有40米大刀。多次触发节流函数,就相当于当前有多个守卫进行排队,而触发的频率过大时,就相当于有其他的守卫进行插队,这时候40米大刀就会清除这些插队的守卫。因此达到每个守卫都好好排队的效果。
- 目的不同
- 防抖的目的在于:控制在一段时间的内的多次冒泡事件,只触发一次
- 节流的目的在于:控制在一段时间的内的多次冒泡事件,在一定的频率上进行触发
思考:
- 防抖和节流都能达到减少高频率触发的问题。
- 了解了两者之间的区别和实现原理后,在什么样的业务场景上使用什么样的方法,会更加的得心应手