debounce-函数防抖:将一个弹簧按下,继续加压,继续按下,只会在最后放手的一瞬反弹。即我们希望函数只会调用一次,即使在这之前反复调用它,最终也只会调用一次而已。
throttle-函数节流:一个水龙头在滴水,可能一次性会滴很多滴,但是我们只希望它每隔 500ms 滴一滴水,保持这个频率。即我们希望函数在以一个可以接受的频率重复调用。
函数防抖
基本思想
某些代码不可以在没有间断的情况下连续重复执行。第一次调用函数,创建一个定时器,在指定的时间间隔之后运行代码。当第二次调用该函数时,它会清除前一次的定时器并设置另一个。如果前一个定时器已经执行过了,这个操作(清除定时器)就没有任何意义。然而,如果前一个定时器尚未执行,其实就是将其替换为一个新的定时器。目的是只有在执行函数的请求停止了一段时间之后才执行。
基本实现
function debounce(fn, wait) {
let timer;
return function() {
if (timer) {
clearTimeout(timer)
}
timer = setTimeout(() => {
fn.apply(this, arguments)
}, wait)
}
}
函数节流
throttle-函数节流:一个水龙头在滴水,可能一次性会滴很多滴,但是我们只希望它每隔 500ms 滴一滴水,保持这个频率。即我们希望函数在以一个可以接受的频率重复调用。
function throttle(fn, wait) {
let previous = 0; // 用于记录上一次执行的时间
return function() {
let now = +new Date();
let remain = wait - (now - previous);
if (remain < 0) {
previous = now;
fn.apply(this, arguments)
}
}
}
事件第一次触发的时候我要执行该函数,事件停止后,也要再触发一次函数。
function throttle(fn, wait, options = {}) {
let previous = 0; // 用于记录上一次执行的时间
let timeout;
return function() {
let now = +new Date();
let remain = wait - (now - previous);
if (remain < 0) {
if (previous === 0 && !options.begin) {
previous = now;
return
}
if (timeout) {
clearTimeout(timeout);
timeout = null;
}
previous = now;
fn.apply(this, arguments)
} else if (!timeout && options.end) {
timeout = setTimeout(() => {
fn.apply(this, arguments);
timeout = null;
}, wait)
}
}
}
这样就完成了强大的节流函数了, 第一次来的时候,可以执行一次回调函数,结束的时候也会执行一次回调函数。并且可以通过options来配置。
如果设置了options.begin === true就第一触发事件就立刻会执行回调函数。因为我们设置previous的的初始值为0,所以如果previous === 0就表示是第一次触发该事件,与上options.begin就可以得出第一次是否执行该回调函数。
如果设置了options.end === true事件停止触发后也会执行一次该回调函数。其实在事件触发的整个时间内,定时器中的回调函数从来都没有被执行过,只有在事件停止出发后,定时器内的回调函数才被执行。只要设置了options.end就相当于只是用计算时间的方式来实现节流。