防抖:所谓防抖,就是指触发事件后,把触发非常频繁的事件合并成一次去执行。即在指定时间内只执行一次回调函数,如果在指定的时间内又触发了该事件,则回调函数的执行时间会基于此刻重新开始计算。
解释:你尽管触发事件,但是我一定在事件触发 n 秒后才执行,如果你在一个事件触发的 n 秒内又触发了这个事件,那我就以新的事件的时间为准,n 秒后才执行。总之,就是要等你触发事件 n 秒内不再次触发事件,我才执行。
/* 第一版 */
function debounce(fn, delay) {
return function {
fn.timeId && clearTimeout(fn.timeId)
fn.timeId = setTimeout(fn, delay)
}
}
/* 第二版:修复 this 指向问题 */
function debounce(fn, delay) {
return function() }
const _self = this
fn.timeId && clearTimeout(fn.timeId)
fn.timeId = setTimeout(() => {
fn.apply(_self)
}, delay)
}
/* 第三版:修复 event 事件对象问题 */
function debounce(fn, delay) {
return function(...args) {
const _self = this
fn.timeId && clearTimeout(fn.timeId)
fn.timeId = setTimeout(() => {
fn.apply(_self, args)
}, delay)
}
}
/* 第四版:立即执行,不用等到事件停止触发时才执行(加个 immediate 参数判断是否立即执行) */
function debounce(fn, delay, immediate) {
// 保存事件执行结果
let result
return function(...args) {
const _self = this
fn.timeId && clearTimeout(fn.timeId)
// 如果已经执行过,不在执行
if (immediate) {
let callNow = !fn.timeId
fn.timeId = setTimeout(() => {
// 执行后,指定时间内没有继续触发事件则初始化 timerId ,方可继续执行下一次
fn.timeId = null
}, delay)
if (callNow) {
result = fn.apply(_self, args)
}
} else {
fn.timeId = setTimeout(() => {
fn.apply(_self, args)
}, delay)
}
return result
}
}
/* 第五版:加入取消防抖延时,继续触发功能 */
function debounce(fn, delay, immediate) {
let result
const debounced = function(...args) {
const _self = this
fn.timeId && clearTimeout(fn.timeId)
if (immediate) {
let callNow = !fn.timeId
fn.timeId = setTimeout(() => {
fn.timeId = null
}, delay)
if (callNow) {
result = fn.apply(_self, args)
}
} else {
fn.timeId = setTimeout(() => {
fn.apply(_self, args)
}, delay)
}
return result
}
// 取消防抖延时
debounced.cancel = function() {
clearTimeout(fn.timeId)
fn.timeId = null
}
return debounced
}