防抖
防抖技术即是可以把多个顺序地调用合并成一次,也就是在一定时间内,规定事件被触发的次数。
通俗一点来说,看看下面这个简化的例子:
// 简单的防抖动函数
function debounce(func, wait, immediate) {
// 定时器变量
var timeout;
return function() {
// 每次触发 scroll handler 时先清除定时器
clearTimeout(timeout);//清除掉上一次的定时器回调函数,上次事件也就不会执行了。在500ms内,再次滚动,那上次的就清除掉了,不会执行。
// 指定 xx ms 后触发真正想进行的操作 handler
timeout = setTimeout(func, wait);
};
};
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
复制代码
采用了防抖动
window.addEventListener('scroll',debounce(realFunc,500));
封装上面的函数,更简洁
防抖动函数
function debounce(func, wait, immediate) {
var timeout;
return function() {
var context = this, args = arguments;
var later = function() {
timeout = null;
if (!immediate) func.apply(context, args);
};
var callNow = immediate && !timeout;
clearTimeout(timeout);
timeout = setTimeout(later, wait);
if (callNow) func.apply(context, args);
};
};
var myEfficientFn = debounce(function() {
// 滚动中的真正的操作
}, 250);
// 绑定监听
window.addEventListener('resize', myEfficientFn);
复制代码
防抖:
注意:上面的500ms,意思是:两次滚动事件的相隔时间必须大于500ms才能触发成功,而且是倒数第二次的事件触发成功的。如果所有的事件触发的时间间隔都小于500ms,那么就不会触发事件回调函数了,只有最后一次的事件回调能成功执行。
复制代码
节流(Throttling)
-
防抖函数确实不错,但是也存在问题,譬如图片的懒加载,我希望在下滑过程中图片不断的被加载出来,而不是只有当我停止下滑时候,图片才被加载出来。又或者下滑时候的数据的 ajax 请求加载也是同理。
-
这个时候,我们希望即使页面在不断被滚动,但是滚动 handler 也可以以一定的频率被触发(譬如 250ms 触发一次),这类场景,就要用到另一种技巧,称为节流函数(throttling)。
- 节流函数,只允许一个函数在 X 毫秒内执行一次。
-
与防抖相比,节流函数最主要的不同在于它保证在 X 毫秒内至少执行一次我们希望触发的事件 handler。
-
与防抖相比,节流函数多了一个 mustRun 属性,代表 mustRun 毫秒内,必然会触发一次 handler ,同样是利用定时器,看看简单的示例:
// 简单的节流函数
function throttle(func, wait, mustRun) {
var timeout,
startTime = Date.parse(new Date());//重点,这里是在页面加载后就执行的。不是等到滚动才执行。
console.log(startTime);
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
// 如果达到了规定的触发时间间隔,触发 handler
if(curTime - startTime >= mustRun){
func.apply(context,args);
startTime = curTime;//重置开始时间startTime,把它设置成当前的时间
// 没达到触发间隔,重新设定定时器
}else{
timeout = setTimeout(func, wait);
}
};
};
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
// 采用了节流函数
window.addEventListener('scroll',throttle(realFunc,500,1000));
复制代码
上面简单的节流函数的例子可以拿到浏览器下试一下,大概功能就是如果在一段时间内 scroll 触发的间隔一直短于 500ms ,那么能保证事件我们希望调用的 handler 至少在 1000ms 内会触发一次。
注意:强调这句话:保证事件我们希望调用的 handler 至少在 1000ms 内会触发一次。最多也是一次。也就是说,在所有滚动事件的每两个相隔时间都加起来,从开始到结束滚动,每隔1000ms就是触发一次。比如从开始到结束,共经历1分钟,每隔1秒调用一次,总共大概调用60次。
复制代码
参考链接: