之前项目中有遇到过这样一个问题,项目中需要监听一个滚动事件然后触发相应的操作,但是滚动操作是一个高频操作,而且触发的边界条件并不能严格控制触发的频率,所以会造成事件被高频词的触发,会造成页面的卡顿等问题。然后研究了一下解决方案,发现有两个概念,节流与防抖。
函数的节流与防抖主要的作用都是用来限制一个方法被频繁的调用,以达到优化性能的目的。
debounce (函数防抖)
会在第一次调用函数之后(不会立即执行函数)创建一个定时器,在指定时间之后再运行该函数。如果在函数运行之前再次调用,那么定时器会被重置。
实现代码:
/**
* 防抖
* @param {function} fn
* @param {number} delay
*/
function debounce(fn, delay) {
let timer;
return function() {
if (timer) clearTimeout(timer);
let _this = this;
let args = arguments;
timer = setTimeout(() => {
fn.apply(_this, args);
}, delay)
};
}
使用样例:
function logTime() {
console.log(new Date());
}
window.onscroll = debounce(logTime, 600);
以上样例代码是在页面滚动时添加的防抖函数,只有在用户停止滚动之后600ms之后才会执行logTime
动作。在滚动过程中是不会执行动作的。
throttle (函数节流)
实现代码:
/**
* 节流
* @param {function} fn
* @param {number} intervalTime
*/
function throttle(fn, intervalTime) {
let flagTime = 0;
return function() {
let nowTime = Date.now();
if (nowTime - flagTime > intervalTime) {
fn();
flagTime = Date.now();
}
};
}
使用样例:
const logTime = () => {
console.log(new Date());
}
window.onscroll = throttle(logTime, 1000);
以上样例代码在页面滚动时会每隔1s打印一次时间。
总结
防抖会把高频的函数调用转化成最后一次函数调用间隔时间后执行,列如电梯上人只有最后一个人上了没人再上来,电梯等一会再关门出发,如果一直上人(。。。不可能一直上)那么电梯永远不会出发(这里的电梯指的是带门的那种,不是商场的扶梯(()。可以用在页面滚动触发事件的操作上,或者input
输入之后ajax
发请求验证。
节流就是把高频高作转化成一定频次的间隔执行,控制函数的调用频率。可以用在需要实时计算的一些操作上,比如鼠标拖拽操作时计算位置等。