防抖(debounce)
所谓防抖,就是指触发事件后在 n 秒内函数只能执行一次,如果在 n 秒内又触发了事件,则会重新计算函数执行时间。
通俗点来说,就是指用户频繁触发的时候,只执行一次事件(执行第一次或最后一次)【可以设置频繁的间隔时间】。
目的:频繁触发中只执行一次;
应用场景:按钮点击
模拟情景:当点击按钮的时候,期望500ms后输出hello,那么如果在500ms内疯狂点击多次,会发现最后输出多次hello;
那么如何在500ms内只触发一次事件,输出一次hello呢?
思路:设置间隔时间500ms,第一次点击后没有立即执行,等待500ms,观察500ms内是否触发了第二次,如果触发第二次就说明是频繁点击,不去执行函数,如果没有触发第二次则认为非频繁点击,此时去执行函数。依此类推观察第三次和第二次的间隔......
在间隔时间内,只要频繁点击了就清空上次定时器,重新计时。
function func(){
console.log('hello');
}
btn.onclick = function(){
...
}
实现:
前面提到了时间间隔,那么需要借助setTimeout函数以及柯理化函数来实现,具体过程:
/*
* debounce:实现函数的防抖(目的:频繁触发中只执行一次)
* @params
* func:需要执行的函数
* wait:检测防抖的间隔频率
* immediate:是否立即执行(true控制第一次触发时执行函数,默认false是以最后一次触发为准)
* @return
* 返回一个可被调用执行的函数
*/
function debounce(func, wait = 500, immediate = false) {
let timer = null;
return function anonymous(...params) {
//判断立即执行的条件,并非immediate=true就立即执行,需要判断此时是否设置了定时器
//只有第一次执行,需要判断timer的值来区分是第一次还是第二次
let now = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(() => {
timer = null;
// 执行函数:注意保持THIS和参数的完整度
!immediate ? func.call(this, ...params) : null;
}, wait);
now ? func.call(this, ...params) : null;
};
}
最后调用我们实现的防抖函数测试效果,发现和预期效果一样:在500ms内多次点击仅执行一次事件,输出一次hello。
btn.onclick = debounce(func);
节流(throttle)
所谓节流,就是指连续触发事件但是在 n 秒中只执行一次函数。
通俗点来说,节流会缩减频率。
目的:频繁触发中缩减频率;
应用场景:滚动条 window.onscroll / 输入框实时搜索 / onresize
模拟场景:页面中当滚动条滚动时,触发多次scroll事件,页面很长会执行几十次、几百次......
思路:如何缩减频率呢?可以设置一个执行间隔时间,比如500ms,也即是我们希望在指定时间间隔500ms内执行一次scroll事件,直到过了这个期限才重新生效,这样原本执行100次的可能只需要执行20次。
实现:
/*
* throttle:实现函数的节流(目的:频繁触发中缩减频率)
* @params:
* func:需要执行的函数
* wait:自己设定的间隔事件(频率)
* @return
* 返回一个可被调用执行的函数
*/
function throttle(func, wait = 500) {
let timer = null,
previous = 0; //记录上一次操作时间
return function anonymous(...params) {
let now = new Date(), //当前操作的时间
remaining = wait - (now - previous); //剩余时间
if (remaining <= 0) {
// 两次间隔时间超过频率,把方法执行
clearTimeout(timer);
timer = null;
previous = now;
func.call(this, ...params);
} else if (!timer) { //当前定时器不存在才设置,防止多次设置定时器
// 两次间隔时间没有超过频率,说明还没有达到触发标准,设置定时器等待(还差多久等多久)
timer = setTimeout(() => {
clearTimeout(timer);
timer = null;
previous = new Date();
func.call(this, ...params);
}, remaining);
}
};
}
防抖和节流的区别
防抖:防止抖动-----执行一次(次数) 节流:降低频率-----执行多次(频率)
一句话可以概括为:防抖是将多次执行变为第一次执行或最后一次执行,节流是将多次执行变为每隔一段时间执行。
相同点:防抖和节流都能有效减少浏览器引擎的损耗,防止出现页面堵塞卡顿现象。