聊聊对浏览器的认知(三):浏览器的渲染流程

有一次面试,面试官问完_从输入URL到页面展示,这中间发生了什么?本人对答如流,面试官微微一笑,问浏览器的渲染流程是怎么样的呢**?_**那一刻静的太可怕。赶紧回家整理一番。

渲染流程就是指:浏览器拿到编译好的js,html,css是怎么渲染成页面的。

1. 渲染流水线

渲染机制过于复杂,渲染模块会把执行过程划分成很多的子阶段,经过这些子阶段,html才最终输出为像素。这样的一个处理流程就叫做渲染流水线。

流水线可分为如下几个子阶段:构建 DOM 树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成

2. 各个子阶段

构建DOM树

由于浏览器无法直接识别和使用HTML,所以需要将HTML转换为浏览器可以理解的DOM树,如下图。

图片获取于网络非作者原创

样式计算

样式计算目的是,计算出DOM节点中元素的具体样式,分为三步执行。

  • 浏览器同样不能直接使用css,需要转换成styleSheets,在Chrome控制台输入document.styleSheets,就可以看到转换后的结构。
  • 我们经常用到1em,blue, bold这样的值,其实渲染引擎是 不理解这些值的,所以就需要进行标准化计算,如下图。
  • 接下来,就是计算出DOM树每个节点的具体样式。进行样式计算时需要遵循两个规则:继承和层叠,继承就是基层父节点的样式,层叠是指合并多个源的属性值的算法。

图片获取于网络非作者原创

布局阶段

当DOM树和DOM树中元素的样式就位之后,还需要计算出DOM元素的几何位置信息,这个过程就叫做布局。该阶段分两步:创建布局树和布局计算。

  • DOM树中有许多不可见的元素(head标签,使用display:none的等),所以还需要生成一个可见的布局树,浏览器主要做的工作是,遍历DOM树,把可见的节点加入到布局树中。
  • 接下来就是布局计算,这个过程非常复杂,大佬们可以在留言区指教。

创建布局树图片获取于网络非作者原创

分层阶段

我们开发的页面中,总会有一些3D效果,滚动等效果。对于这种情况,渲染引擎还需要为特定的元素节点生成对应的图层,并生成一颗图层树。在Chrome的开发者工具,选择“Layers”标签,就可以看到当前页面分层的情况。

  • 浏览器的页面实际上被分成了很多图层,这些图层叠加后合成了最终的页面。

  • 并不是每一个节点都包含一个图层,如果一个节点没有对于的图层,那么这个节点就从属父节点的图层。

  • 拥有层叠上下文的属性会被单独提升到一层。

  • 还有当div中的文字过多,渲染引擎就需要进行裁剪换行,这时候文字就在单独的一个图层,如果有滚动条,滚动条也会单独提升到一个图层。

                                      层叠上下文的属性

图层绘制阶段

举个例子:如果给一张纸,先把纸的背景涂成蓝色,然后在中间位置画一个红色的圆,最后再在圆上画个绿色三角形。会怎么操作呢?

通常,就是分解为三步:

1. 绘制蓝色背景;

2. 在中间绘制一个红色的圆;

3. 再在圆上绘制绿色三角形。 

渲染引擎实现图层绘制和这个例子差不多,把图层绘制拆分成很多小的绘制指令。如下图,可以看出绘制的指令比较简单。

图片获取于网络非作者原创

在Chrome开发者工具,打开”Layers”,选择“document”层,就可用看到绘制指令的列表。

栅格化(raster)操作

上面我们讲到的绘制指令列表,它只是一个描述记录绘制的列表,实际的绘制工作是由渲染引擎中的合成线程来完成的。

图片获取于网络非作者原创

主线程把绘制列表提交给合成线程,进而进行绘制工作。

我们浏览器窗口尺寸是有限的(视口),对于图层较大的页面,很多内容是“暂时性隐藏“”的(滚动区域),这种情况下一下子渲染出所有的图层,势必造成渲染开销太大,而且对于视口之外内容也没有必要一并渲染。

所以,**合成线程会把图层划分为图块,会按照视口附近的图块来优先生成位图,那么生成位图的操作就是由栅格化来执行的,栅格化就是将图块转化为位图。**渲染进程会单独开辟出一个栅格化的线程池,所有的图块栅格化都是在线程池完成的。

合成操作

合成已经到了渲染的最后一个步骤,一旦所有的图块被栅格化,合成线程就会向浏览器进程发送一个绘制图块的命令。浏览器进程中的viz组件接受到命令后,将页面内容绘制到内存中,最后将内存内容显示到屏幕上。

                                                      完整的渲染流程

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享