浅析浏览器渲染过程

本文主要是记录下浏览器(chrome)的渲染过程,想到什么写什么。

简单划分的浏览器渲染步骤

  1. 从网页输入URL到构建DOM树
  2. DOM树解析成绘图上下文
  3. 根据绘图上下文生成图像

下面根据这三个步骤来分别简单探索一下。

网页输入URL到构建DOM树

一个老生常谈的问题:从浏览器输入URL到页面渲染完毕,中间发生了哪些事情?(之后单独写一篇总结一下,会补上链接)

这个问题感觉避不开,就简单的写一下,当顺便复习了。

  1. DNS域名解析
  2. 建立TCP连接
  3. 发送HTTP请求
  4. 服务器处理请求
  5. 返回响应结果
  6. 关闭TCP连接
  7. 浏览器解析HTML
  8. 浏览器布局渲染

基本是以上八个阶段,可以看到,浏览器拿到返回数据准备开始解析、渲染界面的步骤从第7步才开始,之前6个步骤都是在进行前后端通信,嗯,这里又想起来三次握手,这个问题暂且不讨论。本文讨论的范围是从第7部开始的解析过程

这里写的浏览器解析HTML实际上对应的就是前面渲染步骤的第一步,构建DOM树
浏览器布局渲染对应的就是前面的后两步。

废话不多说了,进入正题。

首先,浏览器解析HTML或者说构建DOM树这一过程,是由浏览器中的谁处理的呢?
这个过程由浏览器的内核模块(渲染引擎)来处理的。
在这里插入图片描述
上面只是一个简单的示意图,把浏览器内核渲染相关的功能列举了一下,值得一提的是最新的Chrome浏览器的内核由以前的webkit换成了Blink内核,不过对我们理解整个浏览器的渲染国营的影响不大,只是几个流程中理解的对象名称发生了一些变化,后续会提到。

浏览器拿到后端返回的资源后,开始对资源进行解析,为什么这里又说是资源,不说是HTML了,因为后端返回的可能不仅仅是HTML,可能还有CSS、JS文件等等,所以浏览器不光是对HTML进行解析,还有CSS、JS等文件都会进行处理,本文为了省事,就简单按照上面图片包含的内容分析了,有兴趣的可以去深入了解一下。

又跑偏了,还是扔图看吧,简单直观。
在这里插入图片描述
以上就是我所理解的整个流程,在当前我们讨论的生成DOM树这一步,经过了JavaScript引擎,因为JS中可能会有一些影响DOM结构的DOM操作,还有可能对DOM的样式产生改变。事实上,这一过程比较简单,若深究DOM树的生成原理,请自行研究内核的相关原理,这里就不展开了(我也不会 =。=)

DOM树解析为绘图上下文

这个过程是我们要研究的重点内容。
上一个步骤中通过HTML解释器生成的DOM树,会和CSS解释器对css样式产生的css rules tree进行“对应粘贴”,生成一个等待处理的Render Tree。其中css rules tree 是CSS解释器对css样式解析成的树形数据结构,它会和DOM树中的对应的节点进行“粘贴”操作,或者说绑定操作,使得样式和DOM节点能够一一对应起来。

接下来是重头戏了。我想丢个图,表达我对这个过程的重视。
上面图中把它放在渲染的步骤中,有些不合适,但是这样有助于理解整个过程,我就不作过多的纠正,与其说是过程,不如说是一种映射关系。
在这里插入图片描述

从Nodes(Render Tree)到Layout Objects

DOM树(RenderTree)中每个Node节点上都会有一个Layout Object,这个Layout Object知道对应的Node节点应该在屏幕上渲染在哪个位置(布局),或者说它知道它对应的节点应该渲染在哪一个渲染层上(Paint Layer)

从 Layout Objects 到 Paint Layers

一般来说,对于拥有相同的空间坐标的Layout Objects来说,它们会共同属于一个Paint Layer(渲染层)。

关于渲染层,又想到一个概念:层叠上下文(stacking contest),这也是个值得探究的话题。Paint Layers起初是用来实现层叠上下文的,这样可以保证页面元素正确的合成(composite)顺序和展示效果。

根据创建Paint Layer的原因,可以将它分为3类:

  1. Normal Paint Layer
  2. Overflow Clip PaintLayer
  3. No Paint Layer
    在这里插入图片描述
    满足以上条件的 Layout Object 会拥有独立的渲染层,而其他的 Layout Object 则和其第一个拥有渲染层的父元素共用一个。

上述流程中最后一步提到了composite的概念。这是因为某些特殊的渲染层会被认为是合成层(Compositing Layers),合成层拥有单独的 GraphicsLayer,而其他不是合成层的渲染层,则和其第一个拥有 GraphicsLayer 父层公用一个。

而每个GraphicsLayer(合成层单独拥有的图层) 都有一个 GraphicsContext,GraphicsContext 会负责输出该层的位图,位图是存储在共享内存中,作为纹理上传到 GPU 中,最后由 GPU 将多个位图进行合成,然后显示到屏幕上。这个就是我们前面第三步将绘图上下文生成图像的这一过程。

如何变成合成层

满足以下任意情况便会创建层:

  • 3D 或透视变换(perspective transform) CSS 属性
  • 使用加速视频解码的 元素 拥有 3D
  • (WebGL) 上下文或加速的 2D 上下文的 元素
  • 混合插件(如 Flash)
  • 对自己的 opacity 做 CSS动画或使用一个动画变换的元素
  • 拥有加速 CSS 过滤器的元素
  • 元素有一个包含复合层的后代节点(换句话说,就是一个元素拥有一个子元素,该子元素在自己的层里)
  • 元素有一个z-index较低且包含一个复合层的兄弟元素(换句话说就是该元素在复合层上面渲染)
合成层的优点

一旦Paint Layer提升为了合成层就会有自己的绘图上下文,并且会开启硬件加速,有利于性能提升。

  • 合成层的位图,会交由 GPU 合成,比 CPU 处理要快
  • 当需要 repaint 时,只需要 repaint 本身,不会影响到其他的层
  • 对于 transform 和 opacity 效果,不会触发 layout 和 paint

注意:

  • 提升到合成层后合成层的位图会交GPU处理,但请注意,仅仅只是合成的处理(把绘图上下文的位图输出进行组合)需要用到GPU,生成合成层的位图处理(绘图上下文的工作)是需要CPU。
  • 当需要repaint的时候可以只repaint本身,不影响其他层,但是paint之前还有style, layout,那就意味着即使合成层只是repaint了自己,但style和layout本身就很占用时间。
  • 仅仅是transform和opacity不会引发layout 和paint,那么其他的属性不确定。

总结合成层的优势:一般一个元素开启硬件加速后会变成合成层,可以独立于普通文档流中,改动后可以避免整个页面重绘,提升性能。

性能优化点:

  • 提升动画效果的元素 合成层的好处是不会影响到其他元素的绘制,因此,为了减少动画元素对其他元素的影响,从而减少paint,我们需要把动画效果中的元素提升为合成层。 提升合成层的最好方式是使用 CSS 的 will-change属性。从上一节合成层产生原因中,可以知道 will-change 设置为opacity、transform、top、left、bottom、right 可以将元素提升为合成层。
  • 使用 transform 或者 opacity 来实现动画效果, 这样只需要做合成层的合并就好了。
  • 减少绘制区域 对于不需要重新绘制的区域应尽量避免绘制,以减少绘制区域,比如一个 fix 在页面顶部的固定不变的导航header,在页面内容某个区域 repaint 时,整个屏幕包括 fix 的 header 也会被重绘。而对于固定不变的区域,我们期望其并不会被重绘,因此可以通过之前的方法,将其提升为独立的合成层。减少绘制区域,需要仔细分析页面,区分绘制区域,减少重绘区域甚至避免重绘。

利用合成层可能踩到的坑

  • 合成层占用内存的问题
  • 层爆炸,由于某些原因可能导致产生大量不在预期内的合成层,虽然有浏览器的层压缩机制,但是也有很多无法进行压缩的情况,这就可能出现层爆炸的现象(简单理解就是,很多不需要提升为合成层的元素因为某些不当操作成为了合成层)。解决层爆炸的问题,最佳方案是打破 overlap 的条件,也就是说让其他元素不要和合成层元素重叠。简单直接的方式:使用3D硬件加速提升动画性能时,最好给元素增加一个z-index属性,人为干扰合成的排序,可以有效减少chrome创建不必要的合成层,提升渲染性能。

总结:以上就是本文的全部内容,后面关于性能优化的部分都是参考前辈的经验文章作笔记,带上一点自己的思考,学一点东西。

参考:
https://blog.csdn.net/weixin_40581980/article/details/81453283
https://blog.csdn.net/weixin_34268310/article/details/88859536
https://www.jianshu.com/p/99e450fc04a5

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值