浏览器的工作原理--简析
一、引言
本文摘选自浏览器工作原理这个网站,目的是将这篇文章提炼并分析,致力于易读懂。本文的目的是让你 了解到,从您在地址栏输入 「google.com」直到您在浏览器屏幕上看到 Google 首页的整个过程中都发生了些什么。
二、简介
如今的主流
浏览器有Internet Explorer、Firefox、Safari、Chrome 和 Opera,主要功能
为向服务器发出请求,在浏览器窗口中展示您选择的网络资源。
2.1 浏览器的高层组件
如下图所示:
包括如下所说组件:
- 「用户界面」
- 「浏览器引擎」 - 在用户界面和呈现引擎之间传送指令。
- 「呈现引擎」 - 解析 HTML 和 CSS 内容。
- 「网络」 - 网络调用,其接口与平台无关,并为所有平台提供底层实现。
- 「用户界面后端」 - 用于绘制基本的窗口小部件。其公开了与平台无关的通用接口,而在底层使用操作系统的用户界面方法。
- **JavaScript 解释器 **- 用于解析和执行 JavaScript 代码。
- 「数据存储」 - 持久层。
三、呈现引擎
作用:显示 HTML 和 XML 文档与图片
主流的呈现引擎:
- Firefox 使用的是
Gecko
- Safari 和 Chrome 浏览器使用的都是
WebKit
3.1 呈现引擎的工作流程
如下所示:
步骤简述如下:
解析 HTML 文档,并将各标记转化成“内容树”上的 DOM 节点,同时解析外部 CSS 文件以及样式元素中的样式数据
呈现树包含多个带有视觉属性(如颜色和尺寸)的矩形
“布局”处理阶段,也就是为每个节点分配一个应出现在屏幕上的确切坐标
最后,绘制呈现引擎会遍历呈现树,由用户界面后端层将每个节点绘制出来。
3.2绘制引擎比较
名称 | 树名称 | 术语 |
---|---|---|
WebKit | Render Tree | 布局 |
Gecko | Frame tree | 重排 |
四、解析和 DOM 树构建
4.1 解析器和词法分析器
词法分析
是将输入内容分割成大量标记的过程
语法分析
是应用语言的语法规则的过程
上图解释过程如下:
- 解析是一个
迭代的过程
。通常,解析器会向词法分析器请求一个新标记,并尝试将其与某条语法规则进行匹配
。 - 如果发现了匹配规则,解析器会将一个对应于该标记的节点
添加到解析树
中,然后继续请求下一个标记。 - 如果没有规则可以匹配,解析器就会将标记
存储到内部
,并继续请求标记,直至找到可与所有内部存储的标记匹配的规则。 - 如果找不到任何匹配规则,解析器就会引发一个
异常
。这意味着文档无效,包含语法错误。
4.2 翻译过程
在4.1中描述的过程就是下图中Parsing的具体解释
解析树还不是最终产品。解析通常是在翻译过程中使用
的,而翻译是指将输入文档转换成另一种格式,具体过程是首先将源代码解析成解析树,然后将解析树翻译成机器代码文档。
4.3 词汇和语法的正式定义
词汇通常用正则表达式表示
语法通常使用一种称为 BNF 的格式来定义
4.4 解析器类型
- 自上而下解析器:自上而下的解析器从语法的高层结构出发,尝试从中找到匹配的结构,包括:移位归约解析器
- 自下而上解析器:从低层规则出发,将输入内容逐步转化为语法规则,直至满足高层规则
4.5 自动生成解析器
WebKit 使用了两种非常有名的解析器生成器:用于创建词法分析器的Flex
以及用于创建解析器的Bison
;Flex 的输入是包含标记的正则表达式定义
的文件。Bison 的输入是采用BNF 格式
的语言语法规则。
4.6 针对HTML的解析器
因为HTML语法容错性要求较高,HTML 不能很容易地用解析器所需的与上下文无关的语法来定义,因此所有的BNF 等格式常规语法解析器都不适用于 HTML。
HTML 和 XML 非常相似,但是因为 HTML 的处理更为“宽容
”,它允许您省略某些隐式添加的标记,有时还能省略一些起始或者结束标记等等,因此造成了巨大的区别,而HTML 的正规解析格式为:DTD
(Document Type Definition,文档类型定义)
4.7 HTML DTD(Document Type Definition,文档类型定义)
此格式可用于定义 SGML族的语言。它包括所有允许使用的元素及其属性和层次结构的定义
4.8 DOM(Document Object Model,文档对象模型)
解析器的输出“解析树”是由 DOM 元素
和属性节点
构成的树结构,它是 HTML 文档的对象表示,同时也是外部内容与 HTML 元素之间的接口
4.9 HTML解析算法流程
两个阶段:标记化(tokenization)和树构建(tree construction)
标记化是词法分析
过程,将输入内容解析成多个标记,HTML 标记包括起始标记、结束标记、属性名称和属性值。标记生成器识别标记,传递给树构造器,然后接受下一个字符以识别下一个标记;如此反复直到输入的结束,直到形成树。
4.9.1 标记化算法简介
该算法相当复杂,无法在此详述,就简略说一下:
❝该算法的输出结果是 HTML 标记,但是使用状态机来表示。每一个状态接收来自输入信息流的一个或多个字符,并根据这些字符更新下一个状态。当前的标记化状态和树结构状态会影响进入下一状态的决定,这意味着,即使接收的字符相同,对于下一个正确的状态也会产生不同的结果,具体取决于当前的状态。
❞
例子:
<html>
<body>
Hello world
body>
html>
初始状态是数据状态。遇到字符 <
时,状态改为**“标记打开状态”「。接收一个 a-z
字符会创建“起始标记”,状态更改为」“标记名称状态”**。这个状态会一直保持到接收 >
字符。在此期间接收的每个字符都会附加到新的标记名称上。
遇到 >
标记时,会发送当前的标记,状态改回**“数据状态”「。 标记也会进行同样的处理。目前
html
和 body
标记均已发出。现在我们回到」“数据状态”**。接收到 Hello world
中的 H
字符时,将创建并发送字符标记,直到接收 中的
<
。我们将为 Hello world
中的每个字符都发送一个字符标记。
现在我们回到**“标记打开状态”「。接收下一个输入字符 /
时,会创建 end tag token
并改为」“标记名称状态”「。我们会再次保持这个状态,直到接收 >
。然后将发送新的标记,并回到」“数据状态”**。