浏览器渲染优化
udacity浏览器渲染优化课程学习笔记
关键路径渲染
现在多数设备刷新屏幕的频率都是60帧/秒,如果浏览器花费太多时间才能显示一帧,就会丢失一帧,从而造成屏幕卡顿不流畅,更严重的情况是屏幕卡住导致糟糕的用户体验。
为了实现60帧/秒的顺畅效果,需要让一帧的渲染时间保持在16ms以内,浏览器还需对每帧进行处理,所以需要在10~12ms完成所有的任务并及时渲染每帧。
单个帧渲染过程
1、浏览器向服务器发送HTTP请求数据
2、服务器响应,并发送一些HTML,浏览器优先解析HTML生成Dom Tree
3、结合HTML和CSS生成Render Tree(渲染树),Render Tree和Dom Tree十分相似,只是只显示在网页上出现的内容,比如head,script等标签不会出现在Render Tree之中,包括设置了display:none的元素也会从Render Tree中移除,而一些伪元素,包括:after,:before则会出现在Render Tree中
4、计算布局、空间和位置
5、绘制,填充像素
布局与绘制
当网页完成之后,需要对网页外观进行改变,有以下几种情况
ps:opacity和transform通常用于单个的图层合成,首先确保要合成的元素都有正确的图层,通过控制opacity和transform来改变外观,只需合成即可。
APP的生命周期
网络应用的生命周期:加载、闲置、动画、响应
加载:初始的加载应该在1s之内完成,下载渲染关键资源
闲置:初始加载完成之后,应该在这段时间处理因为满足1s初始加载而延迟的工作,确保能及时响应接下来的用户操作,这段时间大概有50ms
动画:用户滚动屏幕或是出现动画,需要16ms来渲染一帧
响应:用户与应用交互,点击按钮网页作出响应,响应应在100ms内完成
JS优化动画
js会导致样式布局重绘合成,所以我们需要在每帧开始时执行js,尽早执行完js意味着有足够的时间完成剩下的工作,根据60帧/秒的频率,一帧的js部分通常应该最长保持在3~4ms。
requestAnimationFrome()方法告诉浏览器您希望执行动画并请求浏览器在下一次重绘之前调用指定的函数来更新动画。该方法使用一个回调函数作为参数,这个回调函数会在浏览器重绘之前调用。
requestAnimationFrome会安排js尽早在每帧开始执行以便留下足够的时间给浏览器处理剩下工作。
不使用setTimeout和setInterval来处理动画,因为这两个函数来使用时不会关注渲染管道,在处理动画时应该使用requestAnimationFrome来代替(IE9及以下不兼容使用setTimeout),使用方法
function animate() {
// other code
window.requestAnimationFrame(animate);
}
window.requestAnimationFrame(animate);
Web Workers
Web Workers可以为运行时间长的脚本提供一个后台线程,完全独立运行不会影响到主线程,因此在网页中运行时间长的脚本可以放到Web Workers中,等待处理完成之后再显示结果。
样式和布局
元素数量对性能影响
更改元素样式的成本随着元素的多少呈现线性变化,也就是说改变的元素越多,性能消耗越大,减少受影响的dom元素可以提升性能。
选择器
在为元素匹配css选择器时,类匹配是现代浏览器最快速的匹配选择器,越复杂的选择器,浏览器就需要多次在Dom Tree上下移动,找到正确元素所花费的时间就越多,简化选择器也是一种提升性能的方法。
强制同步布局
divs.forEach(function(elem, index, arr) {
if(window.scrollY < 200) { // 获取导航条会导致运行布局
elem.style.opacity = 0.5;
}
});
divs.forEach(function(elem, index, arr) {
var wid = otherElem.offsetWidth;
elem.style.width = wid = 'px'; // 获取宽度也会导致运行布局
});
上面一段代码,每次循环获取一次导航条或宽度再赋值,当我们访问某些属性时,也会导致布局流程,具体可以看这个属性列表,先运行布局,再重新计算样式,然后再运行布局,这样反复读写导致强制布局错误,页面出现卡顿,好的解决办法是先获取必要的属性,再执行循环,将scrollY和offsetWidth在循环外获取并用一个变量存储起来,再循环能很好的提升性能。
合成与绘制
好的分层能更好的提升用户体验,比如,讲左滑出的导航条和主页面分为不同的层,在用户进行左划时,只需设置导航条层的transform属性,而不会导致页面的重新布局,这样的网页应用符合60帧/秒的频率,但是更多的图层所需要的管理图层时间也就越多,我们需要在绘制时间和增加管理图层之前作出权衡。
will-change
在页面显示某些效果比如视觉滚动落差或是使用大量动画时,页面的绘制性能可能没有达到60帧/秒,使用will-change属性,浏览器会为接下来的动画先创建新的图层,从而提升性能,目前只有部分浏览器支持这个属性,在其他浏览器可以使用transform:translateZ(0)做兼容,3D转换在z空间变化零,没有转换,但是会让浏览器创建新的图层。