Browser under the macro perspective: 05 | rendering pipeline (on): HTML, CSS and JavaScript, is how to become a page?

Preface: This article Description: See  description - the browser works with the practice directory

  

  In the previous article , we introduced the relevant navigation process, and that navigation was submitted and then what will happen? We entered the rendering stage. This stage is important to understand the relevant processes allows you to "see through" how the page works, with this knowledge, you can solve a series of related issues, such as proficiency in the use of developer tools, it can be understood as developer tools inside meaning most projects, optimize page Caton problem, use JavaScript animation to optimize processes to prevent forced synchronization by optimizing the layout style sheets, and so on.

  

  Since its function so powerful, so today, we have to have a conversation  rendering process .

  

  Usually, we write good HTML, CSS and JavaScript files, through the browser displays a beautiful page (as shown below), but you know how they are converted into page do? Principle behind this, estimated that many people could not answer.

Schematic rendering process

  As can be seen from the figure, the left input HTML, CSS, JavaScript data, the intermediate data after processing rendering module, the final output for the pixels on the screen.

 

  This is the middle of the rendering module is the subject we are discussing today. In order to better understand the following, you can quickly grasp the first figure below in conjunction with HTML, CSS and JavaScript meanings:

HTML, CSS and JavaScript diagram

  As can be seen from the figure, the HTML content is composed of marks and text . Mark, also known as tags, each has its own semantics, the browser will correctly display HTML content based on semantic labels. For example, the above <p> tag tells the browser content here is the need to create a new paragraph, middle of the text is the content displayed in paragraph needs.

  

  If you need to change the HTML font color, size and other information, you need to use CSS. Also called CSS Cascading Style Sheets, is selected by the selector attributes and attribute values applications, such as in FIG p selector, it will HTML content inside <p> tags is selected, and then the selector to <p > label content on. Selector which has a color attribute whose value is red, which is to tell the rendering engine the contents of <p> tags are shown in red.

 

  As  JavaScript (referred to as the JS), it can make use of the page contents "move" , such as the figure above, may be modified by the JavaScript CSS style value, so as to achieve the purpose of modifying text color.

 

  After figuring out the meaning of HTML, CSS and JavaScript, then the next we begin the formal analysis of the rendering module.

 

  Since the rendering mechanism is too complicated, rendering module in the implementation process will be divided into many sub-stages, input HTML through these sub-stages, the final output pixel. We call such a process flow is called rendering pipeline , which is generally flow as shown below:

Schematic rendering pipeline

  In chronological order rendering, the pipeline may be divided into the following sub-stages: constructing a DOM tree, computing style, the layout stage, stratified, drawing, block, and synthetic rasterization. More content, I will use two articles to explain this to you in detail the various sub-phases. Next, in the course description of each stage, you should focus on the following three points:

  • The beginning of each sub-stage has its input content ;
  • Then each stage has its sub- process ;
  • The final stage of each child generates output.

  I understand these three parts, allowing you to more clearly understand each sub-phase.

 

Build a DOM tree

  为什么要构建 DOM 树呢?这是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构 —— DOM 树

 

  这里我们还需要简单介绍下什么是树结构。为了更直观地理解,你可以参考下面我画的几个树结构:

树结构示意图

 

  从图中可以看出,树这种结构非常像我们现实生活中的 “树”,其中每个点我们称为 节点,相连的节点称为 父子节点。树结构在浏览器中的应用还是比较多的,比如下面我们要介绍的渲染流程,就在频繁地使用树结构。

 

  接下来我们还是言归正传,来看看DOM树的构建过程,你可以参考下图:

DOM 树构建过程示意图

 

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

 

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

DOM 可视化

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

 

  那下面就来看看如何通过 JavaScript 来修改 DOM 的内容,在控制台中输入:

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

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

通过 JavaScript 修改 DOM

  从图中可以看出,在执行了一段修改第一个 <p> 标签的 JavaScript 代码后,DOM 的第一个 p 节点的内容成功被修改,同时页面中的内容也被修改了。

 

  好了,现在我们已经生成DOM树了,但是 DOM节点的样式我们依然不知道,要让DOM 节点拥有正确的样式,这就需要样式计算了。

 

样式计算(Recalculate Style)

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

 

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

那 CSS 样式的来源主要有哪些呢?你可以先参考下图:

HTML 加载 CSS 的三种方式

  从图中可以看出,CSS 样式来源主要有三种:

  • 通过 link 引用的外部 CSS 文件
  • <style> 标记内的 CSS
  • 元素的 style 属性内嵌的 CSS

 

  和 HTML 文件一样,浏览器也是无法直接理解这些纯文本的 CSS 样式,所以当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构 —— styleSheets

  

  为了加深理解,你可以在 Chrome 控制台中查看其结构,只需要在控制台中输入 document.styleSheets,然后就看到如下图所示的结构:

styleSheets

  从图中可以看出,这个样式表包含了很多种样式,已经把那三种来源的样式都包含进去了。当然样式表的具体结构不是我们今天讨论的重点,你只需要知道渲染引擎会把获取到的 CSS 文本全部转换为 styleSheets 结构中的数据,并且该结构同时具备了查询和修改功能,这会为后面的样式操作提供基础。

 

2. 转换样式表中的属性值,使其标准化

  现在我们已经把现有的 CSS 文本转化为浏览器可以理解的结构了,那么接下来就要对其进行属性值的标准化操作

 

  要理解什么是属性值标准化,你可以看下面这样一段CSS 文本:

body { font-size: 2em }
p { color: blue }
span { display: none }
div { font-weight: bold }
div p { color: green }
div { color: red }

  可以看到上面的 CSS 文本中有很多属性值,如 2em、blue、bold,这些类型数值不容易被渲染引擎理解,所以需要将所有值转换为渲染引擎容易理解的、标准化的计算值,这个过程就是属性值标准化。

 

  那标准化后的属性值是什么样子的?

标准化属性值

  从图中可以看到,2em 被解析成 32px,red 被解析成了 rgb(255, 0, 0),bold  被解析成了 700……

 

3. 计算出 DOM 树中每个节点的具体样式

  现在样式的属性已被标准化了,接下来就需要计算 DOM 树中每个节点的样式属性了,如何计算呢?

 

  这就涉及到 CSS 的继承规则和层叠规则了

 

  首先是 CSS 继承。CSS继承就是每个 DOM 节点都包含有父节点的样式。这么说可能有点抽象,我们可以结合具体例子,看下面这样一张样式表是如何应用到 DOM 节点上的。

body { font-size: 20px }
p { color: blue }
span { display: none }
div { font-weight: bold; color: red }
div p { color: green }

  这张样式表最终应用到 DOM 节点的效果如下图所示:

计算后 DOM 的样式

 

  从图中可以看出,所有子节点都继承了父节点样式。比如 body 节点的 font-size 属性是 20, 那 body 节点下面的所有节点的 font-size 都等于 20。

 

  为了加深你对 CSS 继承的理解,你可以打开 Chrome 的 “开发者工具”,选择第一个 “element” 标签,再选择 “style” 子标签,你会看到如下界面:

样式的继承过程界面

  这个界面展示的信息很丰富,大致可描述如下。

  • 首先,可以选择要查看的元素的样式(位于图中的区域 2  中),在图中的第 1 个区域中点击对应的元素,就可以在下面的区域查看该元素的样式了。比如这里我们选择的元素是 <p>标签,位于 html.body.div. 这个路径下面。
  • 其次,可以从样式来源(位于图中的区域 3  中)中查看样式的具体来源信息,看看是来源于样式文件,还是来源于 UserAgent 样式表。这里需要特别提下 UserAgent 样式,它是浏览器提供的一组默认样式,如果你不提供任何样式,默认使用的就是 UserAgent 样式。
  • 最后,可以通过区域 2 和 区域 3 来查看样式继承的具体过程。

 

  以上就是 CSS 继承的一些特性,样式计算过程中,会根据 DOM 节点的继承关系来合理计算节点样式。

 

  样式计算过程中的第二个规则是样式层叠。层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。它在 CSS 处于核心地位,CSS 的全称 “层叠样式表” 正是强调了这一点。关于层叠的具体规则这里就不做过多介绍了,网上资料也很多,你可以自行搜索学习。

 

  总之,样式计算阶段的目的是为了计算出 DOM 节点中每个元素的具体样式,在计算过程中需要遵守 CSS 的继承和层叠两个规则。这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内。

 

  如果你想了解每个 DOM 元素最终的计算样式,可以打开 Chrome 的 “开发者工具” ,选择第一个 “element” 标签,然后再选择 “Computed” 子标签,如下图所示:

DOM 元素最终计算的样式

  上图红色方框中显示了 html.body.div.p 标签的 ComputedStyle 的值。你想要查看哪个元素,点击左边对应的标签就可以了。

 

布局阶段

  现在,我们由 DOM 树 和 DOM 树中元素的样式,但这还不足以显示页面,因为我们还不知道DOM 元素的几何位置信息。那么接下来就需要计算出DOM树中可见元素的几何位置,我们把这个计算过程叫做布局

 

  Chrome 在布局阶段需要完成两个任务:创建布局树和布局计算。

 

1. 创建布局树

  你可能注意到了 DOM 树还含有很多不可见的元素,比如 head 标签,还有使用了 display:none 属性的元素。所以在显示之前,我们还要额外的构建一棵只包含可见元素布局树

 

  我们结合下图来看看布局树的构造过程:

布局树构造过程示意图

 

  从上图可以看出,DOM树中所有不可见的节点都没有包含到布局树中。

 

  为了构建布局树,浏览器大体上完成了下面这些工作:

  • 遍历DOM树中的所有可见节点,并把这些节点加到布局中;
  • 而不可见的节点会被布局树忽略掉,如 head 标签下面的全部内容,再比如 body.p.span 这个元素,因为它的属性包含 display:none ,所以这个元素也没有被包进布局树。

 

2. 布局计算

  现在我们有了一棵完整的布局树。那么接下来,就要计算布局树节点的坐标位置了。布局的计算过程非常复杂,我们这里先跳过不讲,等到后面章节中我再做详细的介绍。

 

  在执行布局操作的时候,会把布局运算的结果重新写回布局树中,所以布局树既是输入内容也是输出内容,这是布局阶段一个不合理的地方,因为在布局阶段并没有清晰地将输入内容和输出内容区分开来。针对这个问题,Chrome 团队正在重构布局代码,下一代布局系统叫 LayoutNG,试图更清晰地分离输入和输出,从而让新设计的布局算法更加简单。

 

总结

  好了,今天正文就到这里,我画了下面这张比较完整的渲染流水线,你可以结合这张图来回顾下今天的内容。

渲染流水线图

  从图中可以看出,本节内容我们介绍了渲染流程的前三个阶段:DOM生成、样式计算和布局。要点可大致总结为如下:

  • 浏览器不能直接理解HTML数据,所以第一步需要将其转换为浏览器能够理解的DOM树结构;
  • 生成DOM树后,还需要根据 CSS 样式表,来计算出 DOM 树所有节点的样式;
  • 最后计算 DOM 元素的布局信息,使其都保存在布局树中。

  

  到这里我们的每个节点都拥有了自己的样式和布局信息,那么后面几个阶段就要利用这些信息去展示页面了,由于篇幅限制,剩下的这些阶段我会在下一篇文章中介绍。

 

思考时间

  最后,留个思考题:如果下载 CSS 文件阻塞了,会阻塞 DOM 树的合成吗?会阻塞页面的显示吗?

  

作者回答:

当从服务器接收HTML页面的第一批数据时,DOM解析器就开始工作了,在解析过程中,如果遇到了JS脚本,如下所示:
<html>
    <body>
        极客时间
        <script>
        document.write("--foo")
        </script>
    </body>
</html>
那么DOM解析器会先执行JavaScript脚本,执行完成之后,再继续往下解析。

那么第二种情况复杂点了,我们内联的脚本替换成js外部文件,如下所示:
<html>
    <body>
        极客时间
        <script type="text/javascript" src="foo.js"></script>
    </body>
</html>
这种情况下,当解析到JavaScript的时候,会先暂停DOM解析,并下载foo.js文件,下载完成之后执行该段JS文件,然后再继续往下解析DOM。这就是JavaScript文件为什么会阻塞DOM渲染。

我们再看第三种情况,还是看下面代码:
<html>
    <head>
        <style type="text/css" src = "theme.css" />
    </head>
    <body>
        <p>极客时间</p>
        <script>
            let e = document.getElementsByTagName('p')[0]
            e.style.color = 'blue'
        </script>
    </body>
</html>
当我在JavaScript中访问了某个元素的样式,那么这时候就需要等待这个样式被下载完成才能继续往下执行,所以在这种情况下,CSS也会阻塞DOM的解析。


所以JS和CSS都有可能会阻塞DOM解析,关于详细信息我们会在后面的章节中详细介绍。

 

Guess you like

Origin www.cnblogs.com/bala/p/12112431.html