持续触发事件时(比如window的resize事件,滚动事件等),保证每次实际触发的间隔不少于 wait 时间
function throttle(fn, wait) {
let previous = 0
return function(...args) {
const now = new Date().valueOf()
if (now - previous > wait) {
previous = now
fn.apply(this, args)
}
}
}
执行测试代码
setInterval(throttle(() => {
console.log(new Date().getSeconds())
}, 1000), 50)
测试结果:
2
3
4
5
6
7
8
9
持续触发事件监听时(比如input、window.resize, 页面滚动),无论触发了多少次回调,都只执行最后一次(在停止触发事件后间隔 wait 时间后触发)
function debounce(fn, wait) {
// 缓存一个定时器
const context = this
let timer = null
return function(...args) {
if (timer) {
// 如果有上一次触发生成的timer, 则清空该定时器,防止到时执行回调函数
clearTimeout(timer)
}
// 设定一个新的定时器,到时执行回调函数(如果没有后续的触发导致定时器被清空的话)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}
执行测试代码,并缩放窗口大小
const hander = debounce(() => {
console.log('@@@@ fn 执行防抖了')
}, 1000)
window.addEventListener('resize', hander)
function debounce(fn, wait, immediate) {
// 缓存一个定时器
const context = this
let timer = null
return function(...args) {
if (timer) {
// 如果有上一次触发生成的timer, 则清空该定时器,防止到时执行回调函数
clearTimeout(timer)
}
// 新增部分,如果没有 timer 并且 immediate 为真,则立即触发回调函数
if (!timer && !!immediate) {
fn.apply(context, args)
}
// 设定一个新的定时器,到时执行回调函数(如果没有后续的触发导致定时器被清空的话)
timer = setTimeout(() => {
fn.apply(context, args)
}, wait)
}
}