前端有很多频繁触发的事件,例如:input,scroll,resize等,频发触发事件会造成不必要的性能浪费,为了避免这种情况经常采用防抖和节流的方式来处理,这里可以根据自己的需要来进行选择.因为之前也对防抖和节流的概念有所混淆,所以现在也想将自己的理解分享下.
对防抖和节流的理解
防抖: 事件触发n秒后执行,如果在n秒内再次触发了事件,重新计时n秒后执行(一直执行,一直不触发)
节流: 事件n秒内只执行一次,在本次n秒过后才会再次执行一次(稀释事件频率)
防抖函数
function debounce(fun, wait=500) {
// 创建timer,使用到闭包去保存,这样下次执行时也可以获取到timer
let timer
// 返回的方法是触发的事件,我们需要在这个方法里调用我们真正的逻辑事件,即fun
return function (...args) {
// 及时清理没有执行的延时器,保证最后一次触发后n秒才会执行事件
timer && clearTimeout(timer)
timer = setTimeout(() => {
// 延时n秒后触发事件
// 修改事件中的this,并将相应的参数传递给事件,比如event
fun.apply(this, args)
}, wait)
}
}
节流函数
// 根据时间戳计算时间差,来判断是否触发逻辑
function throttle1(fun, wait=500) {
// 闭包保存初始时间
let startTime = 0
return function(...args) {
let nowTime = Date.now()
// 获取当前时间,计算出时间差
if (nowTime - startTime > wait) {
// 当时间差大于节流设置的时间间隔,触发真正的逻辑
fun.apply(this, args)
// 给初始时间赋值,以计算下次执行的时间
startTime = nowTime
}
}
}
// 利用延时器控制逻辑触发
function throttle2(fun, wait=500) {
// 闭包保存保存延时器的变量
let timer
return function(...args) {
if (!timer) {
// 延时器不存在的时候,设置n秒后触发真正逻辑
// 延时器存在说明已经有在等在执行的逻辑
timer = setTimeout(() => {
fun.apply(this, args)
// 执行后,恢复初始值,下次再次执行
timer = null
}, wait)
}
}
}
两个节流函数使用效果的区别: 1触发事件后会立刻执行一次,停止触发事件后不在执行 2触发事件后不会立即执行,要在n秒后执行第一次,停止触发后会在触发一次事件