前言:图片懒加载、下滑加载数据、侧边浮动导航栏等常常需要监听scroll事件,或者resize事件,频繁触发repaint reflow,CPU负荷很重。
解决方法:
setTimeout
1. 防抖 Debouncing
加上setTimeout让操作延时
// 简单的防抖动函数
function debounce(func, wait, immediate) {
// 定时器变量
var timeout;
return function() {
// 每次触发 scroll handler 时先清除定时器
clearTimeout(timeout);
// 指定 xx ms 后触发真正想进行的操作 handler
timeout = setTimeout(func, wait);
};
};
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
// 采用了防抖动
window.addEventListener('scroll',debounce(realFunc,500));
2. 节流 Throttling
如果想要在一定时间内被触发,要使用节流函数
节流函数:只允许并且保证一个函数在 X 毫秒内执行一次。
// 简单的节流函数
function throttle(func, wait, mustRun) {
var timeout,
startTime = new Date();
return function() {
var context = this,
args = arguments,
curTime = new Date();
clearTimeout(timeout);
// 如果达到了规定的触发时间间隔,触发 handler
if(curTime - startTime >= mustRun){
func.apply(context,args);
startTime = curTime;
// 没达到触发间隔,重新设定定时器
}else{
timeout = setTimeout(func, wait);
}
};
};
// 实际想绑定在 scroll 事件上的 handler
function realFunc(){
console.log("Success");
}
// 采用了节流函数
window.addEventListener('scroll',throttle(realFunc,500,1000));
requestAnimationFrame
使用 requestAnimationFrame 触发滚动事件, 会在页面重绘之前调用。适用于高级浏览器和复杂的场景。
window.requestAnimationFrame(function(){
...whatever
})
简单来说,rAF是一个优化的定时器。可以不仅限于动画制作。被调用的频率是每秒 60 次,也就是 1000/60,触发频率大概是 16.7ms 。(当执行复杂操作时,当它发现无法维持 60fps 的频率时,它会把频率降低到 30fps 来保持帧数的稳定。)
throttle(func, xx, 1000/60)
总结
防抖动:将多次调用合并为一次(这段时间内不一定会执行)
节流函数:一定时间内只允许知行一次。
rAF:16.7ms 触发一次,降低了可控性,但是提升了性能和精确度。
优化
1.
- 可以在外面初始化的变量就别放进来了
- 尽量不要修改样式属性。scroll中修改会被浏览器暂存。requestAnimationFrame一开始修改样式,会强制同步布局。
2. pointer-events: none 禁止鼠标事件
添加属性后,鼠标点击和hover都将失效。可以调滚动时的帧频