在我的博客从url输入到页面渲染:导航流程:导航流程中主要介绍了浏览器端的网络请求过程,完成了网络请求和响应,如果响应头中Content-Type的值为text/html,那么接下来便是浏览器对于服务器返回响应数据的解析和渲染,这个过程主要可以分为如下几个子阶段:构建DOM树、样式计算、布局阶段、分层、绘制、分块、光栅化和合成。下面我们就各个阶段深入了解:
由于浏览器无法直接理解HTML字符串,因此将这一系列的字节流转换成一种有意义并且方便操作的数据结构,这种数据结构就是DOM树,DOM树本质上是一个以document为根节点的多叉树。
那么通过什么样的方式来进行解析呢?
HTML文法的本质:
首先,我们应该清楚把握一点:HTML的文法并不是上下文无关文法
,什么是上下文无关文法
呢?
在编译原理学科中对于其的定义为:
若一个形式文法G = (N, Σ, P, S) 的产生式规则都取如下的形式:V->w,则叫上下文无关语法。其中 V∈N ,w∈(N∪Σ)* 。
其中把 G = (N, Σ, P, S) 中各个参量的意义解释一下:
通俗一点讲,上下文无关文法
就是说这个文法中所有产生式的左边都是一个非终结符,举个例子:
A -> B
这个文法中,每个产生式左边都会有一个非终结符,这就是上下文无关文法
。在这种情况下,xBy一定是可以规约出xAy的。
aA -> B
Aa -> B
这种情况就不是上下文无关文法
,当遇到B的时候,我们不知道到底能不能规约出A,取决于左边或者右边是否有a存在,也就是说和上下文有关。
那么HTML为什么不是上下文无关文法
,实际上规范的 HTML 语法,是符合上下文无关文法的,能够体现它非上下文无关的是不标准的语法。
比如解析器扫描到form标签的时候,上下文无关文法
的处理方式是直接创建对应 form 的 DOM 对象,而真实的 HTML5 场景中却不是这样,解析器会查看 form 的上下文,如果这个 form 标签的父标签也是 form, 那么直接跳过当前的 form 标签,否则才创建 DOM 对象。
常规的编程语言都是上下文无关的,而HTML却相反,也正是它非上下文无关的特性,决定了HTML Parser并不能使用常规编程语言的解析器来完成,需要另辟蹊径。
HTML解析算法:
HTML5 规范详细地介绍了解析算法。这个算法分为两个阶段:
对应的两个过程就是词法分析和语法分析。
1、标记化
标记化是词法分析过程,这个算法输入为HTML文本,输出为HTML标记,也称为标记生成器。HTML 标记包括起始标记、结束标记、属性名称和属性值。
标记生成器运用有限自动状态机来完成,状态机一共有4个状态:
有限自动状态机在当前状态下,接收一个或多个字符,就会更新到下一个状态,通过4个状态之间的切换标记生成器识别标记,传递给树构造器,然后接受下一个字符以识别下一个标记;如此反复直到输入的结束。
我们通过如下示例演示该过程:
<html>
<body>
Hello world
body>
html>
<
, 状态为标记打开。[a-z]
的字符,会进入标记名称状态。>
,表示标记名称记录完成,这时候变为数据状态
中的>
,进入数据状态,之后保持这样状态接收后面的字符hello world。
中的<
,回到标记打开状态,接收下一个/
后,这时候会创建一个end tag
的token。>
回到数据状态。