什么是防抖和节流?有什么区别?如何实现?
一、防抖
场景:在滚动事件中需要做个复杂计算或者实现一个按钮的防二次点击操作。这些需求都可以通过函数防抖动来实现。尤其是第一个需求,如果在频繁的事件回调中做复杂计算,很有可能导致页面卡顿,不如将多次计算合并为一次计算,只在一个精确点做操作。
一般的防抖会有immediate选项,表示是否立即调用。
// 思路:在规定时间内未触发第二次,则执行
function debounce (fn, delay) {
// 利用闭包保存定时器
let timer = null
return function () {
let context = this
let arg = arguments
// 在规定时间内再次触发会先清除定时器后再重设定时器
clearTimeout(timer)
timer = setTimeout(function () {
fn.apply(context, arg)
}, delay)
}
}
function fn () {
console.log('防抖')
}
addEventListener('scroll', debounce(fn, 1000))
整体函数实现的不难,总结一下。
1.对于按钮防点击来说的实现:如果函数是立即执行的,就立即调用,如果函数是延迟执行的,就缓存上下文和参数,放到延迟函数中去执行。一旦我开始一个定时器,只要我定时器还在,你每次点击我都重新计时。一旦你点累了,定时器时间到,定时器重置为 null,就可以再次点击了。
2.对于延时执行函数来说的实现:清除定时器ID,如果是延迟调用就调用函数
二、节流
1.防抖动和节流本质是不一样的。防抖动是将多次执行变为最后一次执行,节流是将多次执行变成每隔一段时间执行。
2.高频事件触发,但在 n 秒内只会执行一次,所以节流会稀释函数的执行频率
// 思路:在规定时间内只触发一次
function throttle(fn, delay) {
// 函数触发第一次触发的时间
let data = new Date()
// 利用闭包保存一下时间
return function () {
// 保存一下全局window对象
let context = this
// 保存参数
let arg = arguments
// 当前函数执行的时间
let now = new Date()
// 如果函数执行的时间减去他上一次执行的时间大于我要防的时间,则执行函数
if (now - data >= delay) {
// 执行函数
fn.apply(context, arg)
data = Date.now()
}
}
}
function fn() {
console.log('节流')
}
addEventListener('scroll', throttle(fn, 1000))