前言
防抖和节流总体上来说是减少函数的执行次数,优化浏览器的性能,因为有些功能不需要频繁的执行。例如onClick事件,onScroll事件。但二者不同,让我们来分别看看他们的具体功能。
函数的防抖
对于频繁触发某个操作,我们只识别一次,即只触发执行一次函数。
主体思路
在当前点击完成后,我们等待一段的时间,看是否还会触发第二次,如果没有触发第二次,属于非频繁操作,我们直接执行想要执行的函数func;如果触发了第二次,则以前的不算了,从当前这次再开始等待...
function debounce(func, wait = 300, immediate = false) {
let timer = null;
return function anonymous(...params) {
let now = immediate && timer === null;
// 每次点击都把之前设置的定时器清除
clearTimeout(timer);
// 重新设置一个新的定时器监听wait时间内是否触发第二次
timer = setTimeout(() => {
// 手动让其回归到初始状态
timer = null;
// wait这么久的等待中,没有触发第二次
!immediate ? func.call(this, ...params) : null;
}, wait);
// 如果是立即执行
now ? func.call(this, ...params) : null;
};
}
参数:
- func[function]:最后要触发执行的函数;
- wait[number]:“频繁”设定的界限;
- immediate[boolean]:默认多次操作,我们识别的是最后一次,但是immediate=true,让其识别第一次
通过闭包返回一个可以被调用执行的函数
不采用防抖:
function handle() {
console.log("OK");
}
submit.onclick = handle
点击多少次就执行多少次
采用防抖:
submit.onclick = debounce(handle, 300, true);
肉眼可以看到减少了执行次数
函数节流
在一段频繁操作中,可以触发多次,但是触发的频率由自己指定。
function throttle(func, wait = 300) {
let timer = null,
previous = 0; // 记录上一次操作的时间
return function anonymous(...params) {
let now = new Date();
let remaining = wait - (now - previous); //记录还差多久达到我们一次触发的频率
if (remaining <= 0) {
// 两次操作的间隔时间已经超过wait了
timer = null;
previous = now;
func.call(this, ...params);
// 通过!timer判断是否进入下一次函数执行,如果上一次没有执行,则拒绝执行
} else if (!timer) {
// 两次操作的间隔时间还不符合触发的频率
timer = setTimeout(() => {
timer = null;
previous = new Date();
func.call(this, ...params);
}, remaining);
}
};
}
以onscroll函数来测试:
window.onscroll = handle; //每一次滚动过程中,浏览器有最快反应时间(5~6ms 13~17ms),只要反应过来就会触发执行一次函数(此时触发频率5ms左右)
可以看到onscroll事件绑定的函数被多次触发。
接下来使用节流包装的handle函数来测试
window.onscroll = throttle(handle);
可以看到onscroll事件绑定的函数只触发了十次左右。
总结
防抖和节流减少了函数执行次数,优化了浏览器性能。 点击事件一般采用防抖。滚动、文本框输入事件采用节流。