前端性能优化-渲染优化
一、现代浏览器网页渲染原理——关键渲染路径(critical rendering path)
这个过程无论首次加载还是后续操作都会经历这样的过程。
浏览器渲染页面过程:
1、浏览器构建对象模型:
(1)构建DOM对象:HTML=>DOM
(2)构建CSSOM对象:CSS=>CSSOM
2、浏览器构建渲染树:DOM、CSSOM合并成Render Tree。
该过程主要是减少树结构,将不需要显示如display:none的节点剔除掉,减少计算开支。
3、执行关键渲染路径
(1)计算JS所改变的DOM结构或者布局等变化。
(2)样式改变的结构和变化。
(3)Layout布局,布局是计算每个节点精确的位置和大小-”盒模型“。
(4)Paint绘制,绘制是像素化每个节点的过程。
(5)Composite复合,将绘制的东西分层,最后将所有层整合一个展示给用户。
执行关键渲染路径的优化点是有些样式是不需要经历Layout和Paint,而Layout和Paint也是开销最大的两步,这个优化也是面试常问的如何减少回流和重绘。
影响Layout回流的操作:
1、添加、删除元素
2、display:none
3、移动元素位置
4、操作styles
5、offsetLeft、scrollTop、clientWidth
6、修改浏览器大小,字体大小
layout thrashing(布局抖动)是常见的回流问题,layout thrashing(布局抖动)是连续不断的强制回流导致。
如何解决layout thrashing(布局抖动):
1、避免回流
2、读写分离,原理就是将布局更改一次性进行更改,如vnode虚拟dom,FastDom工具库等都可以实现读写分离的操作。
Composite复合拆分图层后,每个图层不影响其他图层,所以优化思路是将需要回流重绘的拆分出图层。
控制台可以在Layers下查看页面拆分的图层。
浏览器有自己默认规则进行拆分图层,那如何用代码来自定义拆分图层?
willChange:'transform',这个css属性配置可以告诉浏览器这个节点提取成单独的图层。
以下属性只会触发复合,不会触发回流重绘,并且会拆分为单独的图层:
transform:translate()
transform:scale()
transform:rotate()
opacity
注意,我们只对我们需要的进行图层的拆分,不要将所有元素都拆分成独立图层,这样复合消耗的性能远比回流重绘大。
如何减少重绘其实跟上面复合优化是相同的,上面复合优化其实已经跳过了重绘操作直接进行复合。
其他优化方法:
1、节流和防抖函数:
每帧动画的生命周期:
在回流和重绘之前,js会帮我们调度rAF的函数,那么我们就可以通过rAF来进行防抖节流操作,来降低触发频率。
React时间调度实现也是借用了requestAnimationFrame模拟requestIdleCallback,即通过rAF模拟rIC。因为rIC兼容性不好所以才采用rAF实现。
rAF是渲染之前发生,而rIC是渲染后发生,这是他们两个的区别如下图: