Appearance
函数防抖(debounce)
在函数需要频繁触发时, 在规定时间内, 只让边界的那一次生效,适合多次事件一次响应的情况。 应用场景: 输入框实时搜索联想
javascript
/**
* 函数防抖 Credits: borrowed code from https://github.com/jashkenas/underscore
*
* @param {Function} fn - 需要进行防抖处理的原函数
* @param {number} wait - 防抖的时间间隔
* @param {boolean} [immediate=false] - 假设 wait 为 1000,再这个时间段内调用了两次
* 防抖函数,如果 immediate 为 false,表示开始边界不触发,结束边界,即触发第二次调用
* 的防抖函数,如果 immediate 为 true,表示开始边界触发,结束边界不触发,即触发第一
* 次调用的防抖函数。
* @returns {Function} - 生成的防抖函数
*/
const debounce = (fn, wait, immediate) => {
let prev = 0, // prev 是上次点击的时间戳,不是 fn 执行的时间戳。
timer = null,
params = null,
result = null,
context = null
const later = () => {
const remaining = wait - (now() - prev)
if (remaining > 0) {
// 还需要等 remaining 秒,如果之后又马上点击,又会进入这里,
// 确保点击间隔大于 wait 时才触发。
timer = setTimeout(later, remaining);
} else {
// 点击间隔大于 wait 时进入这里,如果设置了开始边界触发,不让它执行。
if (!immediate) {
result = fn.call(context, ...params)
}
timer = null
}
}
const _debounce = function (...args) {
prev = now() // 更新上次点击时间
context = this
params = args
if (!timer) {
timer = setTimeout(later, wait)
// 开始边界触发
if (immediate) {
result = fn.call(context, ...params)
}
}
return result
}
_debounce.cancel = () => {
clearTimeout(timer)
timer = context = params = null
}
return _debounce
}javascript
const now = _.now()
const foo = () => {
console.log(_.now() - now)
}
const bar = _.debounce(foo, 1000)
setTimeout(() => {
bar() // 不触发,因为没设置开始边界触发。
}, 0)
setTimeout(() => {
bar() // 不触发,距离上次点击间隔没超过 1000 ms
}, 500)
setTimeout(() => {
bar() // 不触发,距离上次点击间隔没超过 1000 ms
}, 1200)
setTimeout(() => {
bar() // 3200 ms 触发,因为是结束边界触发。
}, 2200)javascript
const now = _.now()
const foo = () => {
console.log(_.now() - now)
}
const bar = _.debounce(foo, 1000, true)
setTimeout(() => {
bar() // 0 ms 触发,因为设置了开始边界触发。
}, 0)
setTimeout(() => {
bar() // 不触发,距离上次点击间隔没超过 1000 ms
}, 500)
setTimeout(() => {
bar() // 不触发,距离上次点击间隔没超过 1000 ms
}, 1200)
setTimeout(() => {
bar() // 2300 ms 触发,因为设置了开始边界触发。
}, 2300)