渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记

1、概括 

渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第1张图片

 我们知道HTMLCSSJavaScript 数据,经过中间渲染模块的处理,最终输出为屏幕上的像素。                              

HTML的内容是由标记文本组成。标记也称为标签,每个标签都有它自己的语义,浏览器会根据标签的语义来正确展示 HTML 内容。比如上面的

标签是告诉浏览器在这里的内容需要创建一个新段落,中间的文本就是段落中需要显示的内容。如果需要改变 HTML 的字体颜色、大小等信息,就需要用到 CSS。

CSS又称为层叠样式表,是由选择器和属性组成,比如图中的 p 选择器,它会把 HTML 里面

标签的内容选择出来,然后再把选择器的属性值应用到

标签内容上。选择器里面有个 color 属性,它的值是 red,这是告诉渲染引擎把

标签的内容显示为红色。

JavaScript(简称为 JS),使用它可以使网页的内容“动”起来,比如上图中,可以通过 JavaScript 来修改 CSS 样式值,从而达到修改文本颜色的目的。

由于渲染机制过程主要划分为 DOM 树样式计算布局阶段分层绘制分块光栅化合成

 2、构建 DOM 树

由于浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树

渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第2张图片

 从图中可以看出,构建 DOM 树的输入内容是一个非常简单的 HTML 文件,然后经由 HTML 解析器解析,最终输出树状结构的 DOM。

为了更加直观地理解 DOM 树,你可以打开 Chrome 的“开发者工具”,选择“Console”标签来打开控制台,然后在控制台里面输入“document”后回车,这样你就能看到一个完整的 DOM 树结构,如下图所示:

渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第3张图片

 图中的 document 就是 DOM 结构,你可以看到,DOM HTML 内容几乎是一样的,但是和 HTML 不同的是,DOM 是保存在内存中树状结构,可以通过 JavaScript 来查询或修改其内容

document.getElementsByTagName("p")[0].innerText = "black"

这行代码的作用是把第一个标签的内容修改为 black,具体执行结果你可以参考下图:

渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第4张图片

 3、样式计算(Recalculate Style)

样式计算的目的是为了计算出 DOM 节点中每个元素的具体样式,这个阶段大体可分为三步来完成。 

3.1把 CSS 转换为浏览器能够理解的结构

CSS 样式来源主要有三种:

  • 通过 link 引用的外部 CSS 文件
  • 所以元素有了层叠上下文的属性或者需要被剪裁,那么就会被提升成为单独一层,你可以参看下图:

    从上图我们可以看到,document层上有A和B层,而B层之上又有两个图层。这些图层组织在一起也是一颗树状结构。

    图层树是基于布局树来创建的,为了找出哪些元素需要在哪些层中,渲染引擎会遍历布局树来创建层树(Update LayerTree)。

     在这里我们把 div 的大小限定为 200 * 200 像素,而 div 里面的文字内容比较多,文字所显示的区域肯定会超出 200 * 200 的面积,这时候就产生了剪裁,渲染引擎会把裁剪文字内容的一部分用于显示在 div 区域,下图是运行时的执行结果:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第12张图片

    出现这种裁剪情况的时候,渲染引擎会为文字部分单独创建一个层,如果出现滚动条,滚动条也会被提升为单独的层。你可以参考下图:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第13张图片

    所以说,元素有了层叠上下文的属性或者需要被剪裁,满足其中任意一点,就会被提升成为单独一层。 

    绘制

    渲染引擎实现图层的绘制会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表,如下图所示:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第14张图片

     从图中可以看出,绘制列表中的指令其实非常简单,就是让其执行一个简单的绘制操作,比如绘制粉色矩形或者黑色的线等。而绘制一个元素通常需要好几条绘制指令,因为每个元素的背景、前景、边框都需要单独的指令去绘制。

    所以在图层绘制阶段,输出的内容就是这些待绘制列表。你也可以打开“开发者工具”的“Layers”标签,选择“document”层,来实际体验下绘制列表,如下图所示:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第15张图片

    在该图中,区域 1 就是 document 的绘制列表,拖动区域 2 中的进度条可以重现列表的绘制过程。

    7 栅格化(raster)操作 

    绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。你可以结合下图来看下渲染主线程和合成线程之间的关系:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第16张图片

    合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。而图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的,运行方式如下图所示:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第17张图片

    通常,栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。

    GPU 操作是运行在 GPU 进程中,如果栅格化操作使用了 GPU,那么最终生成位图的操作是在 GPU 中完成的,这就涉及到了跨进程操作。具体形式你可以参考下图:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第18张图片

    8 合成和显示

    一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。

    浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

    到这里,经过这一系列的阶段,编写好的 HTMLCSSJavaScript 等文件,经过浏览器就会显示出漂亮的页面了。

    9 渲染流水线大总结

    好了,我们现在已经分析完了整个渲染流程,从 HTML 到 DOM样式计算布局图层绘制光栅化合成和显示。下面我用一张图来总结下这整个渲染流程:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第19张图片

     结合上图,一个完整的渲染流程大致可总结为如下:

    • 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。
    • 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。
    • 创建布局树,并计算元素的布局信息。
    • 对布局树进行分层,并生成分层树。
    • 为每个图层生成绘制列表,并将其提交到合成线程。
    • 合成线程将图层分成图块,并在光栅化线程池中将图块转换成位图。
    • 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
    • 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。

    相关概念

    1. 更新了元素的几何属性(重排) 

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第20张图片

    从上图可以看出,如果你通过 JavaScript 或者 CSS 修改元素的几何位置属性,例如改变元素的宽度、高度等,那么浏览器会触发重新布局,解析之后的一系列子阶段,这个过程就叫重排。无疑,重排需要更新完整的渲染流水线,所以开销也是最大的。 

    2. 更新元素的绘制属性(重绘)

    接下来,我们再来看看重绘,比如通过 JavaScript 更改某些元素的背景颜色,渲染流水线会怎样调整呢?你可以参考下图:

    渲染流程关于HTML、CSS和JavaScript的那些事的学习笔记_第21张图片

    从图中可以看出,如果修改了元素的背景颜色,那么布局阶段将不会被执行,因为并没有引起几何位置的变换,所以就直接进入了绘制阶段,然后执行之后的一系列子阶段,这个过程就叫重绘相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。 

    学习资源:

    1、浏览器工作原理与实践

你可能感兴趣的:(前端进阶系列,网络)