返回 登录
0

如何优化浏览器页面渲染(避免浏览器掉帧)

之前做一些resize scroll的效果的时候会出现图像一闪一闪的情况,运动不流畅的情况,后来看了一些资料自己总结了一些解决浏览器掉帧的问题.
还是前端新人一个,说的不对的地方请各位大神多多指教多多包涵~ emoticon

浏览器出现掉帧主要就是因为事件触发过于频繁,浏览器来不及处理导致在下一个事件被触发之前无法完成,特别在scroll resize这样的事件同时又涉及大量DOM操作和元素绘制的时候,浏览器掉帧就会比较严重.

一个页面被浏览器呈现在用户面前之前,浏览器通常会经历:JavaScript的编译,计算样式,布局(layout),为DOM元素填充像素(paint),合并渲染层(DOM元素的绘制是在多个层上进行的,绘制完成后再进行合并),页面生成的时候会被至少渲染(layout+paint)一次,在被访问过程中也会不断地重排和重绘,特别是scroll resize的频繁触发会导致浏览器不停地重新渲染页面,通过元素的分组当某个层内容改变的时候,就可以仅仅重绘这个层,不需要整个页面重绘.
{这里经大神的指教不应该说是”JavaScript的编译”,因为编译主要是指Java C++这些强类型的语言在正式运行之前需要经过编译器编译成机器码再运行,所以应该是说”JavaScript代码的加载和解释”}

也可以通过防抖函数,减少事件在一定时间内的触发次数:
html 代码效果预览


1234567891011121314151617181920212223

封装一下:
html 代码效果预览


10111213141516171819202122232425262728293031323334353637383940
var context = this,args = arguments;
var later = function(){
timer = null;
if(!immediate){
func.apply(context,args);
}
};
var callNow = immediate && !timer;
clearTimeout(timer);
timer = setTimeout(later,wait);
if(callNow){
func.apply(context,args);
}
}
};
var myEfficientFn = debounce(function(){
console.log(‘hi’);
},500);
window.addEventListener(‘scroll’,myEfficientFn);
}

但是防抖函数也存在一些问题,带来一些用户体验不太好的地方,比如图片可能会在用户停止scroll的时候才被加载出来.我们希望即使页面在不断被滚动,但是滚动handler也可以以一定频率被触发,这种技巧被称为节流函数:
只允许一个函数在X毫秒内执行一次,只有当上一次函数执行后过了规定的时间间隔才能进行下一次该函数的调用.在规定时间内至少执行一次我们希望触发的事件handler
如果在一段时间内scroll触发的间隔一直短于100ms,那么能保证事件我们希望调用的handler至少在500ms内会被触发一次
html 代码效果预览


12131415161718192021222324252627282930313233343536373839404142
var context = this;
var args = arguments;
var curTime = new Date();
clearTimeout(timer);
//如果到达了规定的触发时间间隔,触发handler
if(curTime - startTime >= mustRun){
func.apply(context,args);
startTime = curTime;
//没有到达就重新设定定时器
}else{
timer = setTimeout(func,wait);
}
};
};
function realFunction(){
console.log(‘hi’);
}
window.addEventListener(‘scroll’,throttle(realFunction,500,1000))
}

3.使用rAF(requestAnimationFrame)触发滚动事件
如果只需要兼容高版本的浏览器,又或者页面追求高精度的结果,那么可以使用浏览器的原生方法rAF(requestAnimationFrame);

requestAnimationFrame:
window.requestAnimationFrame()这个方法是用来在页面重绘之前,通知浏览器调用一个指定的函数,这个方法接受一个函数为参数,该函数会在重绘前调用,
requestAnimationFrame通常用于web动画的制作,用于准确控制页面的帧刷新渲染,让动画效果更加流畅,同时它也 是一个定时器,被调用的频率是每秒60次,也就是16.7Ms
简单地说,使用requestAnimationFrame来触发滚动事件大概类似于:
throttle(func,xx,16.7)//xx代表在xx ms内不会重复触发事件handler大概功能就是在滚动的过程中,保持以16.7ms的频率触发事件
html 代码效果预览


12345678910111213141516171819202122232425

requestAnimationFrame比节流函数更加适用于复杂的场景,但是存在兼容性方面的问题,而且可控性也不好.

4.简化事件内操作
我们应该简化事件内操作,将一些变量的初始化,不依赖于位置变化的计算等都当在scroll外提前就绪.
1.避免在scroll事件中修改样式属性/将样式属性从scroll事件中剥离
输入事件处理函数,比如scroll/touch事件的处理,都会在requestAnimationFrame之前被调用执行,因此,如果你在scroll事件处理函数中做了样式修改属性的操作,那么这些操作会被浏览器暂存起来,然后调用requestAnimationFrame的时候,如果你在一开始做了读取样式属性的操作,那么这将会触发浏览器的强制同步.
2.滑动过程中尝试使用pointer-events:none 禁止鼠标事件可以提高滚动时的帧频,但是使用该属性后hover click事件会全部失效,要在停止滚动的时候移除掉这个属性

前端学习网站 链接内容
前端e路 链接内容
前端大牛链接内容

评论