前端性能优化-渲染优化


一、现代浏览器网页渲染原理——关键渲染路径(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是渲染后发生,这是他们两个的区别如下图: