现代浏览器揭秘

原文地址:How browsers work

简介

Web浏览器恐怕是用户最多的软件了。本文将介绍浏览器的工作原理。想知道从你在地址栏中输入“google.com”,到窗口中显示Google主页的过程中都发生了什么?本文会为你揭开这个秘密。

要讨论的浏览器

今天,人们主要使用5种浏览器:Internet Explorer、Firefox、Safari、Chrome和Opera。这篇文章的分析源自开源浏览器——Firefox、Chrome和 Safari,Safari是部分开源的。根据W3C对浏览器使用情况的统计信息,当前(2009年10)Firefox、Safari和Chrome共 同的市场占有率已接近60%。因此,可以说开源浏览器已经占据了浏览器市场的半壁江山。

浏览器的主要功能

浏览器的主要功能就是呈现你选择的网络资源,换句话说,就是你向服务器请求资源,然后浏览器把它们显示在自己的窗口中。资源的格式通常是HTML, 当然也有PDF、图像等等。资源的位置是使用URI(Uniform Resource Indentifier,统一资源标识符)来指定的。与此相关的内容在后面讨论网络的时候还会详细介绍。

浏览器如何解释HTML文件是由HTML和CSS规范规定的。这些规范是由W3C(World Wide Web Consortium,万维网联盟)维护的,W3C是负责制定Web标准的组织。

HTML当前的版本号是4(http://www.w3.org/TR/html401/),HTML5还在制定中。CSS当前的版本号是2(http://www.w3.org/TR/CSS2/),CSS3也正在制定过程中。

多少年来,浏览器厂商各自为战,纷纷埋头开发自己的扩展,对规范的支持始终不给力。结果就给Web开发人员带来了生死攸关的兼容性问题。而今天,大多数浏览器对规范的支持程度仍然参差不齐。

浏览器的用户界面大同小异,其中相同的界面元素包括:

  • 用于输入URI的地址栏
  • 后退和前进按钮
  • 书签选项
  • 用于刷新和停止加载当前文档的刷新及停止按钮
  • 返回主页的主页按钮

说来也怪,并没有哪个正式公布的规范对浏览器的用户界面作出规定,浏览器目前的外观是多年来浏览器厂商之间互相模仿和不断改进的结果。HTML5规 范中没有定义浏览器必须具备的UI元素,但列出了一些公共元素,其中就包括地址栏、状态栏和工具栏。当然,有些浏览器还有自己专有的一些功能,如 Firefox的下载管理器。相关的更多内容将在后面讨论用户界面时介绍。

浏览器的主要构成

以下是构成浏览器的主要组件(参考1.1)。
1、用户界面——包括地址栏、后退/前进按钮、书签菜单等等,也就是除了显示所请求页面的主窗口之外的其他所有部分。
2、浏览器引擎——用于查询和操作呈现(rendering)引擎的接口。
3、呈现引擎——负责显示请求的内容,例如请求的内容是HTML,它就负责解析HTML和CSS并将解析后的内容显示到屏幕上。
4、网络模块——用于完成网络调用,如HTTP请求。具有平台中立的接口和针对不同平台的底层实现。
5、UI后端——用于绘制基本的组合选择框及对话框之类的基本部件。具有不特定于某个平台的界面样式,在底层使用的是操作系统的用户界面方法。
6、JavaScript解释器——用户解释和执行JavaScript代码。
7、数据存储模块——属于持久层;浏览器需要在硬盘中保存各种数据,如Cookie。HTML5还为客户端存储定义了新的技术。


图1 浏览器的主要组件

需要特别指出的是,Chrome会为每个新建的标签页创建一个新的呈现引擎的实例,并且每个标签页也运行在独立的进程当中,这一点与其他浏览器不一样。对构成浏览器的这些组件,我们会逐一详细讨论。

组件之间的通信

Firefox和Chroem都具有联系各个组件的组件。后面也将讨论这些组件。

呈现引擎

呈现引擎主要负责……呈现,也就是把请求的内容显示到浏览器屏幕上。

默认情况下,呈现引擎可以显示HTML和XML文档以及图像。而借助插件(一种浏览器扩展)它还可以显示其他类型的内容,比如使用PDF阅读器插件 可以显示PDF。后面我们还会专门讨论插件和扩展,但这里我们只讨论呈现引擎的主要用途——显示使用CSS格式化之后的HTML及图像。

呈现引擎

前面提到的浏览器(Firefox、Chrome和Safari)是构建在两个呈现引擎之上的。Firefox使用Gecko——Mozilla自己开发的一个呈现引擎;Safari和Chrome都使用Webkit。
Webkit是一个开源的呈现引擎,最早是为Linux平台开发的,后来由苹果公司移植到Mac和Windows平台。有关内容请参考http://webkit.org。

主流程

呈现引擎首先通过网络层取得被请求文档的内容。通常是以8K分块的方式完成。

取得内容之后,呈现引擎的基本工作流如下图所示:


图2 呈现引擎的基本工作流

呈现引擎会开始解析HTML文档,并将HTML标签转换成“内容树”中的DOM节点。然后,它开始解析样式数据,包括外部CSS文件和style元素中的样式。解析后的样式信息,再加上HTML中的视觉指令,将被用于创建另一个树——呈现器树

呈现器树中包含着各种矩形,每个矩形都有颜色和大小等属性。这些矩形都按照显示在屏幕上的顺序排列好了。

在构建完呈现器树之后,呈现引擎要完成一个“布局”过程。在这个过程中,它会精确地确定每个节点在屏幕上出现时的坐标。紧接着的一个阶段就是绘制——遍历呈现器树,并使用UI后端层将所有节点逐个绘制出来。

上述过程是逐步完成的,认识到这一点很重要。为了获得更好的用户体验,呈现引擎会尽可能早地将内容呈示到屏幕上。换句话说,它不会等到把所有 HTML标签都解析完毕之后再去构建和布局呈现器树,而是解析完一部分内容,就显示一部分内容;与此同时,剩余内容可能还在通过网络不断下载的过程中。

主流程示例


图3 Webkit的主流程


图4 Mozilla的Gecko呈现引擎的主流程

从图3和图4可以看出,Webkit和Gecko使用的术语稍有不同,但整个流程基本上是相同的。

Gecko把可见的格式化元素的树叫做“框架树”(Frame tree),每个元素都是一个框架。而Webkit使用的则是“呈现器树”(Render tree),这个树由“呈现器对象”构成。Webkit把排列元素叫做“布局”,而Gecko则称该过程为“重排”(Reflow)。同样,“附加” (Attachment)则是Webkit对连接DOM节点与样式信息以创建呈现器树的称呼。Gecko还有一个与语义无关的小差别,它在HTML与 DOM树之间加了一层,叫做“内容渗入”(Content Sink),相当于一个制造DOM元素的工厂。下面我们就来解释流程中的每个阶段。

基本解析

由于解析是呈现引擎的一项非常重要的工作,因此我们会讨论得比较深入一些。首先来简单地介绍一下解析。

所谓的解析文档,就是把文档转换成具有某种意义的结构,以便代码能够被理解和使用。解析之后的结果通常是一个节点树,与文档的结构对应。这个节点树叫做解析树或语法树。

举个例子,解析表达式“2+3-1”会返回下面这个树:


图5 算术表达式的节点树

文法

解析是依据文档所遵循的语法规则进行的,取决于编写文档的语言和格式。每一个要解析的格式都必须具有由词汇表和语法规则构成的文法。这种文法称为上下文无关的文法。人类语言不具备上下文无关的文法,因此无法使用通常的解析技术来解析。

解析器——加上词法分析器

解析可以分为两个步骤:词法分析(lexical analysis)和语法分析(syntax analysis)。

词法分析指的是把输入分解成符号。符号来自语言的词汇表——基本有效单元的集合。对人类语言来说,符号就相当于我们字典中的那些单词。

语法分析就是使用语言的语法规则进行分析。

解析器通常把这两项工作交给两个组件来完成:词法分析器(有时也叫分词器)负责把输入分解成符号,而解析器则负责依据语言的语法规则来分析文档结构,然后构建起解析树。词法分析器知道如何剥离空格、换行等无关字符。


图6 从源文档到解析树

解析过程是迭代进行的。解析器通常会要求词法分析器给出一个新的符号,然后使用该符号去匹配某种语法规则。如果匹配成功,则将与该符号对应的节点添加到解析树中,然后继续要求词法分析器再提供另一个符号。

如果匹配不成功,解析器会在内部保存当前符号,然后继续从词法分析器那里获取符号,直到所有内部保存的符号能够匹配一项语法规则为止。如果最终都没有找到匹配的规则,解析器就会抛出异常。这就意味着文档无效,或者说包含语法错误。

posted @ 2012-06-29 10:33  猫200  阅读(250)  评论(0编辑  收藏  举报