背景
优化高频率事件,降低代码执行频率。有些事件是会频繁触发的:onkeyup、keydown、onscroll、onresize、oninput、mouseMove、等 我不想让它如此的频繁,怎么办呢?
- 我不想让它如此的频繁,只在最后一次事件后触发即可,debounce
- 我依然想让它频繁触发,只不过不要那么频繁, throttle
注:UnderScore 中是 throttle & debounce 两个方法,lodash把2个方法合一起了,封装逻辑稍有复杂
防抖Debounce
一段时间结束后,才能触发一次(so,不适合抢购按钮,用户要一直可以点击),如果一段时间未结束再次触发事件,就会重新开始计算时间
- 应用场景:百度联想查询:不停止输入就不call api,直到停止输入后才call api
- 怎么实现呢? 在事件发生时,取消上一次的定时器,开启新的定时器
/**
* immediate:首次,是否立即执行一次
*/
function debounce(fnc, wait) {
let timeout;
return function () {
clearTimeout(timeout)
if (immediate && !timeout) {
fnc.apply(this, arguments)
}
timeout = setTimeout(() => {
fnc.apply(this, arguments)
}, wait);
}
}
节流throttle
- 场景:1s内的点击了3次,算一次点击,窗口的resize事件
/**
* wait:时间段
* options.trailing=true 最后一次要不要执行
* options.leading=false 第一次要不要执行
*/
function throttle(fn, wait, options) {
let previous = 0; //初始值是0,第一次一定大于wait
let context = this
let args;
let timeout;
let laterFn = function () {
fn.apply(context, args)
previous = options.leading === false ? 0 : Date.now()
timeout = null
}
let throttled = function () {
args = arguments
let now = Date.now()
if (!previous && options.leading === false) {
previous = now
}
let remaining = wait - (now - previous)
if (remaining < 0) {
if (timeout) {
clearTimeout(timeout)
timeout = null
}
fn.apply(context, arguments)
previous = Date.now()
} else if (!timeout && options.trailing) {
timeout = setTimeout(laterFn, remaining);
}
}
return throttled;
}
节流防抖的区别
- 相同点:都是为了降低频率
- 不同点: