From:http://taligarsiel.com/Projects/howbrowserswork1.htm
引子:
浏览器可能是我们最经常使用的软件了。在这章节我将解释浏览器怎么运行的背后。我们将看到当你在地址栏输入google.com后到浏览器打开Google主页这段时间内都发生了什么事情。
我们讨论的浏览器
当今主流浏览器有五类: Internet Explorer, Firefox, Safari, Chrome 以及 Opera。我会基于开源浏览器 Firefox, Chrome 与 Safari(部分开源)来举例说明。按照 W3C 浏览器统计, 当今(2009年10月), Firefox, Safari 及 Chrome 的总占有率已接近 60%,这是非常可观的。
浏览器的主要功能
浏览器的主要功能是展示网页资源,也即请求服务器并将结果显示在浏览器窗口中。资源的格式一般是HTML,但也有PDF、图片等其它各种格式。资源的定位由URL来实现。更多细节请参考“网络”一节。
浏览器释与展现HTML文件的方式是参照HTML与CSS规范来的,这些规范由 W3C (World Wide Web Consortium) Web标准化组织来维护。当前HTML版本是 4 (http://www.w3.org/TR/html401/),HTML5正在进行中。当前CSS版本为2 (http://www.w3.org/TR/CSS2/),同样,版本3进行中。
过去几年里,各版本浏览器有许多各自的扩展,这使网页作者很难写出兼容性好的内容。如今这一严重的兼容性问题已经开始好转,各种浏览器都开始兼容标准规范。
各浏览器的用户接口有很多相同的地方,下面是一些常用的用户接口:
用于输入URI的地址栏
前进后退按钮
书签选项
刷新停止按钮,用于控制页面加载
主页按钮
很奇怪的是,浏览器的用户接口并没有写进任何规范中,这种极大的相似性只是在多年的实践经验以及浏览器之间的相互借鉴中形成的。HTML5规范没有规定浏览器必须有哪些交互元素,但是列出了一些通用元素,比如地址栏, 状态栏和工具栏。当然,特定浏览器有自己独有的特性,如Firefox的下载管理器。更多内容请参考用户接口一节。
浏览器的上层结构
浏览器的主要概念如下 (1.1):
用户接口 – 包括地址栏,前进后退,书签菜单等窗口上除了网页显示区域以外的部分。
浏览器引擎 – 查询与操作渲染引擎的接口。
渲染引擎 – 负责显示请求的内容。比如请求到HTML, 它会负责解析HTML 与 CSS 并将结果显示到窗口中。
网络 – 用于网络请求, 如HTTP请求。它包括平台无关的接口和各平台独立的实现。
UI后端 – 绘制基础元件,如组合框与窗口。它提供平台无关的接口,内部使用操作系统的相应实现。
JavaScript解释器。用于解析执行JavaScript代码。
数据存储。这是一个持久层。浏览器需要把所有数据存到硬盘上,如cookies。新的HTML规范 (HTML5) 规定了一个完整(虽然轻量级)的浏览器中的数据库:’web database’。
layers
图1: 浏览器的主要概念
需要注意的是,与其它浏览器不同,chrome使用多个渲染引擎实例,每个Tab一个,每个Tab都是一个独立进程。
我会使用一个章节来介绍这些组件。
组件间的通信
firefox和chrome开发了一种特别的通信设施,将在另外的章节中讨论
渲染引擎:
渲染引擎的作用是….额,渲染,将内容渲染到浏览器上。
渲染引擎会默认的现实html 和xml 文档还有图片。也可以通过插件(浏览器扩展)现实别的类型文件。举个例子通过pdf 浏览插件显示pdf文档。我们会在另外的章节讨论插件和扩展。在本章中我们重点关注主要适用场景-显示适用css格式化过的html和图片。
渲染引擎
我们提到的浏览器-firefox,chrome 和Safari,它们是构建在两种不同的渲染引擎上,firefox使用Gecko,一个自制的引擎。Safari和chrome都是使用的webkit.
webkit是一个开源的渲染引擎,刚开始是Linux平台引擎,后来经苹果公司修改才支持mac和windows,详细信息可以访问 http://webkit.org.
主流程
渲染引擎通过网络层获得到请求文档,通常是8K大小的数据块。然后渲染引擎的基本流程是这样的:
flow
渲染引擎开始解析html文档,将tag转换成dom树中的节点,通常叫做“内容树”。并且还要解析样式文件,不论外部的还是内嵌的。使用样式信息和html的虚拟结构来创建另外一个树形结构--渲染树。
渲染树包含很多的矩形框,矩形中包含虚拟的属性(比如颜色,尺寸),这些矩形框将按照适当的顺序被渲染的浏览器中。
渲染树的结构渲染完成后将执行布局处理(layout process),这也意味着给每个节点设置在浏览器上显示的坐标,下一个阶段是绘制-渲染树将遍历所有的节点,使用后台布局(UI backend layed)层绘制这些节点.
理解这个平滑的过程是比较重要的。为了更好的用户体验,渲染引擎会尽快的渲染到屏幕上,它不会等到所有的html开始编译和布局前解析。当剩下的来自网络的其他部分内容正在解析是,已经有部分的内容将会解析和展示。
主流程举例
webkitflow
图3webkit的渲染流程
image008
图4发irefox 的gecko渲染流程
从图3和图4我们可以看出尽管webkit和Gecko渲染的过程有些许的不同,但是总体还是相同的。
在Gecko中称这个树形结构为虚拟格式化元素-帧树。每个元素都是一个帧。webkit中称之为“渲染树” ,“渲染树”包含许多渲染对象,webkit使用这些元素布局这些元素,Gecko称为“reflow”。 ‘Attachment(附加组件)’在webkit中链接DOM节点和虚拟信息来创建渲染树。一个次要的非语义化的区别就是在html和DOM树之间Gecko有额外的一层渲染层,叫做“content sink”,这是一个制作DOM 元素的工厂。我们将在下来讨论下每个元素:
解析–这个是通用的
因为解析的过程在渲染引擎中是一个比较重要的过程,所以我们稍微深入地探讨一下。刚开始我们先介绍下解析。
解析文档是将文档部分翻译成一个比较好理解的结构,也就是说引擎代码可以识别。解析的结果通常是一个树形结构,这个树形结构代表了文档的结果,这个就叫做解析树或者叫语法树。
举例说明,解析表达式“2+3-1”可能返回如下的结构:
image009
语法
浏览器解析是建立在文档约束的基础上的,这个约束是规定了书写格式或者语言。每种格式都精确地包括语法和字组。这个格式称为上下文自由语法。人类语言并不是这样所以并不适合使用这种编译技术。
解析-词法分析组合
解析可以分为两个子进程–词法分析和语法分析
词法分析是一个将输入分割成多个标记的进程。标记就是语言词汇-构建可用块元素的集合。
语法分析就是运用语言语法规则。
编译器通常将这个过程分为两部分-词法分析(有时候也称做分词器)它的职责是将输入分割正多个可用的标记。编译器的职责是根据语法规则分析文档结构来构建编译树。词法分析知道去掉不相关的字符,像空格和换行。
image011
解析进程是可迭代的。编译器通常向词法分析器“索取”新的标记并且使用语法规则匹配这个标记,如果匹配成功,一个标记相对应的节点就会被添加到解析上,接下来,编译器继续“索取”。
如果没有匹配到,编译器将先将这个标记存起来,并且继续“索取”标记至到内部存储的所有的标记被一个规则匹配到。如果标记没有匹配到解析器将抛出一个异常,这个异常的意思是这个文档不可用并且包含语法错误。
转换
多次渲染的编译树不是最终的。解析通常用来转换-转换输入文档为别的格式。编译程序就是个例子,编译程序首先将原代码编译成机器码,解析成一个树形结构,存储到机器码文档。
image013
解析的例子
在figure5中我们用数学表达是构建了一个解析树。现在我们定一个一个简单的数学语言来看下解析的过程。
数据字典:我们的语言包含整型,正数和负数。
语法:
1、语言语法可以使用表达式,词语和操作构建块。
2、表达式可以包含任何数字
3、表达式定义为 关系+操作符+关系
4、操作符是正或负
5、关系是一个整型或者表达式
让我们分析下“2+3-1”这个表达式
第一个子串会匹配到“2”,根据前面的提示它是一个词语。第二个匹配项是“2+3”,匹配到第二个规则-词语+操作符+词语。接下来会命中输入项到结尾处。“2+3-1”是一个表达式因为我们已经知道2+3是一个词所以可以加操作符加另外的词语。’2++’并不能匹配到任何一个规则所以是一个非法的输入。
日常词汇和语法定义
省略….
解析器类型
有两种基本的解析器-自上而下解析和自下而上解析器。一个直观的解释是,自上而下解析器看到的语法的高层次结构和尝试匹配他们中的一个。自下而上解析器开始与输入并将其逐渐转变成的语法规则,从低级别规则开始直到高级别规则都得到满足。
让我们来看看这两种解析器会如何解析我们的例子:
自上而下的解析器会从更高的层次规则开始 – 它会识别“2+3”作为一个表达式。然后它将确定的“2 +3 – 1”为表达式(识别表达演变符合其他规则的过程,但开始点是最高级别的规则)。
自底向上解析器将扫描输入,直到一个规则匹配那么它将使用规则取代匹配的输入。这将继续下去,直到输入的结束。部分地匹配的表达式被放置在分析器栈。
这种类型的自下而上解析器被称为移位减少解析器,因为输入被移动到右侧(想象一个指针指向第一个在输入开始和向右移动),并逐渐降低至语法规则。
自动生成解析器
有工具可以生成一个解析器为您服务。它们被称为解析器生成。你给他们你的语言的语法 – 它的词汇和语法规则,他们产生了一个工作解析器。创建解析器需要分析的深刻理解和不易手动创建一个优化的解析器,所以解析器生成器是非常有用的。
的Webkit使用两个知名的解析生成器 – 的Flex创建词法分析器和Bison用于创建解析器(你可能会遇到他们的名字Lex和Yacc)。Flex输入是包含令牌正则表达式定义的文件。Bison’s的输入是BNF格式的语言语法规则。
HTML Parser
HTML解析器的工作是解析HTML标记成解析树。
HTML语法定义
HTML的词汇和语法在W3C组织创建的规范中定义。当前的版本是HTML4。HTML5的工作正在进行中。
不是一个上下文无关语法
正如我们所看到的分析介绍,语法句法可以使用像BNF格式的正式定义。
不幸的是所有的常规解析器主题并不适用于HTML(我并没有给他们带来了只是为了好玩 – 他们将在解析CSS和JavaScript中使用)。 HTML可以不易被上下文无关文法解析器需要限定。
这里是用于限定的HTML正式格式 – 的DTD(文档类型定义) – 但它不是一个上下文无关语法。
这似乎有些别扭 – HTML是相当接近的XML。有很多可用的XML解析器。有HTML的XML变化 – XHTML – 所以有什么大的差别?
不同的是,HTML方式较为“宽容”,它可以让你省略其隐含地添加某些标记,有时省略开始或标签等,总体上它到底是一个“软”的语法,而不是XML的僵硬和苛刻 句法。
显然,这个看似微小的差促使了不同的世界。一方面,这是最主要的原因,HTML是如此受欢迎 – 它原谅你的错误,使网络作者生活更轻松。另一方面,它使得难以写格式的语法。这样总结 – HTML不能容易地解析,而不是通过常规解析器因为其语法不是一个上下文无关文法,也不是由XML解析器。
HTML DTD
HTML定义是在DTD格式。这个格式被用于定义SGML语言家族。该格式包含所有允许的元素,它们的属性和层次结构的定义。正如我们前面所看到的,在HTML DTD没有形成一个上下文无关文法。
DTD有一些变化。严格模式完全符合规范,但其他模式包含用于在过去浏览器的标记支持。其目的是与旧内容的向后兼容性。目前严格的DTD是在这里:http://www.w3.org/TR/html4/strict.dtd
dom
输出树 – 解析树是DOM元素和属性节点树。 DOM是短期的文档对象模型。它是HTML文档的对象表示和HTML元素向外界,像JavaScript的接口。
树的根是“document”对象。
在DOM中具有几乎以一对一的关系的标记。例如,下面的标记:
Hello World
将被转换为下面的DOM树:
image015
如HTML,DOM是由W3C组织指定的。见http://www.w3.org/DOM/DOMTR。它是一个通用的规范操作的文件。一个具体的模块介绍了HTML的具体内容。该HTML定义可以在这里找到:http://www.w3.org/TR/2003/REC-DOM-Level-2-HTML-20030109/idl-definitions.html。
当我说树包含DOM节点,我的意思是树的构建实现了DOM接口中的一个元素。浏览器使用具有使用内部浏览器的其他属性的具体实现。
未完待续。。。。。