浏览器的工作机制

一、概述

  网络浏览器可能是最广泛使用的软件了。本文中我将解释它们在幕后是如何工作的,我们将看到从你在地址栏中输入“google.com”,直到谷歌的页面出现在浏览器屏幕的过程中发生了什么。

  1、我们将要讨论的浏览器

  现在主要有五种浏览器被使用,分别是:IE、火狐、Safari、Chrome和欧朋。根据W3C浏览器的统计资料,目前(2009年9月),Firefox, Safari and Chrome浏览的使用份额总和将近有60%。

因此在当前,开源浏览器是浏览器市场的中坚力量。

  2、浏览器的主要功能

  浏览器主要的功能是展示你所选择的网络资源,通过向服务器请求并显示在浏览器的窗口中。资源的格式通常是HTML,或者PDF、image等等。资源的位置是由用户使用的URI(统一资源标识符)来指定的。浏览器解释和显示HTML文件的方式根据HTML和CSS规范来指定。这些规范是由W3C组织维护的,W3C是网络标准组织。

  当前HTML的版本号是4(http://www.w3.org/TR/html401/),版本5还在制定中。当前的CSS版本号是2(http://www.w3.org/TR/CSS2/),版本3仍在制定中。多年来浏览器只遵循了规范的一部分,并且开发了他们自己的扩展。这给浏览器的使用者带来了严重的兼容性问题。现在绝大部分的浏览器都基本上遵循了规范。

  浏览器的用户界面彼此有很多共同之处,其中常见的用户页面元素有:

  • 写入URI的地址栏
  • 后退和前进按钮
  • 书签选项
  • 用来刷新和停止加载当前文件的刷新和停止按钮

  奇怪的是,浏览器的用户界面没有在任何正式的规范中指定,这些是多年来各浏览器厂商之间相互模仿和不断改进得结果。HTML5规范并没有定义浏览器中必须具有的UI元素,包括地址栏、状态栏和工具栏。还有一些浏览器拥有自己特有的功能,像火狐的下载管理器。

  3、浏览器的主要构成

  浏览器的主要部件有:

  1. 用户界面:包括地址栏、后退和前进按钮、书签菜单等等。也就是除了用来显示你请求页面的主窗口的其他部分。
  2. 浏览器引擎:查询和操作渲染引擎的接口

  3. 渲染引擎: 负责显示请求的内容,例如请求的是HTML内容,它负责解析HTML和CSS并将解析的内容显示在屏幕上。

  4. 网络:用来网络调用,例如HTTP请求,它有平台无关的接口,可以在不同的平台上工作。

  5. 界面后端:用来绘制类似组合选择框及对话框等基本组件,具有不限定于某个平台的通用接口,底层使用操作系统的用户接口。

  6. JS解释器:使用它来解析和执行JS代码。

  7. 数据存储:属于持久层,浏览器需要将各种格式的数据保存在硬盘上,例如cookies。最新的HTML规范(HTML5)定义网络数据库是一种完整的轻量级客户端数据库。

  下面为浏览器的主要构件示意图:

 

  

  ps:需要特别指出的是,不同于大部分浏览器,Chrome为每个标签分配了各自的渲染引擎实例,每个标签就是一个独立的进程。

  对于每一个组件,我将在后面的章节中进行逐一阐述。

  4、组件之间的通信

  Firefox和Chrome都开发了一套特殊的通信结构,后面将有专门的一章进行讨论。

二、渲染引擎

  渲染引擎的职责是…渲染,就是在浏览器屏幕上显示请求的内容。默认情况下,渲染引擎能够显示HTML和XML文件以及图片。通过插件(一种浏览器扩展)可以显示其它类型文件。例如通过使用PDF查看插件显示PDF文件。我们将用一个章节来讨论插件和扩展。这里只讨论渲染引擎最主要的用途——显示应用了CSS之后的HTML和图片。

  1、渲染引擎

  我们所讨论的浏览器:Firefox, Chrome 和 Safari是基于两种渲染器构建的。Firefox使用Gecko一种Mozilla自主研发的渲染引擎。afari 和 Chrome使用的都是Webkit。

  Webkit是一种开源渲染引擎,它一开始是在Linux平台上使用的,后来被Apple改进并应用到Mac及Windows上,更多详情请参考http://webkit.org

  2、主要流程

  渲染引擎首先从网络层获取请求的内容,通常以8K分块的方式完成。

  下面是渲染引擎的基本流程:

  

  渲染引擎首先解析HTML文件,将标签转化为内容树的DOM节点。然后将解析外部CSS文件和style标签中的样式信息。这些样式信息和HTML中的可见性指令将会被用来构建另一颗树—渲染树(渲染树由一些包含有颜色和大小等属性的矩形组成,这些矩形按照正确的顺序显示在屏幕上)

  渲染树构建好之后,将执行布局过程。这将出给每个节点在屏幕上出现的确切坐标。接下来的步骤是绘制—遍历渲染树,并使用后端UI层绘制出每一个节点。

  值得一提的是,这是一个逐步的过程。为了更好的用户体验,渲染引擎将更可能早的将内容显示在屏幕上,而不会等到所有的HTML都解析完之后再去构建和布局渲染树,它是边解析边显示内容的,与此同时还可能通过网络下载余下内容。

  3、主要流程实例

            图 Webkit main flow

  

 

            图 Mozilla's Gecko rendering engine main flow

  

  通过上面两幅图可以看到尽管Webkit和Gecko使用稍微不同的术语,但是流程基本是相同的。Gecko称可见的格式化元素组成的树为frame树。

  每个元素都是一个frame。webkit则使用“Render Tree”这个名词来命名由渲染对象组成的树。Webkit中元素的定位称为布局,而Gecko中称为回流。Webkit称连接DOM节点及样式信息去构建render树的过程为”attachment”,Gecko在html和dom树之间附加了一层,这层称为内容接收器,相当制造DOM元素的工厂。下面将讨论流程中的各个阶段。

、解析和DOM树构建

  1、解析-常规

  因为解析是渲染引擎中一个非常重要的过程,我们将更深入研究一下它。让我们首先介绍一下解析。

  解析一个文件是将其转化为具有一定意义的结构—可以理解和使用的代码。解析的结果通常是一颗表示文件结构的节点树,称为解析树或语法树。

  例子—解析表达式“2+3-1”,可能返回这样一颗树:

  

  语法

  解析基于文档依据的语法规则-文档的语言或格式。每种可被解析的格式必须具有由词汇及语法规则组成的特定文法,称为上下文无关文法。人类语言不具有这一特性,因此不能通过常用的解析技术解析。

  解析器-词法分析器

  解析可以被分为两个子过程-语法分析和词法分析。

  词法分析就是将输入分解为符号。符号是语言的词汇表-有效构建块的集合。对于人类而言,它相当于是我们字典中出现的所有单词。

  语法分析是指对语言应用语法规则。

  解析器通常将工作分配给两个组件-词法分析器负责将输入分解为合法的符号,解析器负责按照语言的语法规则分析文档结构从而构建解析树。词法分析器知道怎么跳过空白和换行之类的无关字符。

  

  解析过程是迭代的。解析通常向词法分析器获取一个新的符号然后试图用这个符号去匹配一条语法规则。如果有一条规则被匹配到,那么这个符号对应的节点将会被添加到解析树中,然后请求另一个符号。如果没有匹配到规则,解析器将在内部保存该符号并继续从词法分析器中获取符号直到所有内部保存的符号能够匹配一条规则。如果最终没有找到匹配的规则,解析器将会抛出一个异常,这意味着文档无效或者包含语法错误。

  转换

  很多时候解析树不是最终的结果。解析一般在转换中使用—将输入文档转化成另一种格式。编译就是一个例子。编译器将源代码编译成机器码,首先将其解析为一颗解析树然后将树转换为机器码文档。

  

  解析实例

  在图表5中,我们从一个数学表达式中构建了一颗解析树。让我们来定义一个简单的数学语言,看看解析的过程。

  词汇表:我们的语言可以包括整数,加号和减号。

  语法:

    1、该语言的语法基本单元包括表达式,术语和操作符。

    2、该语言可以包括多个表达式

    3、一个表达式定义为两个term通过一个操作符连接

    4、一个操作符是一个加号或者一个减号

    5、一个term是一个整数或是一个表达式

  现在来分析一下“2+3-1”这个输入:

  第一个匹配规则的子字符串是“2”,根据规则5这是一个term。第二个匹配的是“2+3”,一个term后跟着一个操作符再连接着另一个term。下一个匹配在输入的结束处。“2+3-1”是一个表达式因为我们已经知道?2+3?是一个term,所以我们有了一个term紧跟着一个操作符及另一个term。“2++”将不会匹配任何规则,因此是一个无效输入

  词汇和语法的正式定义

  词汇通常通过正则表达式来表示。

  例如我们语法将会被定义成: 

  INTEGER :0|[1-9][0-9]*

  PLUS : +

  MINUS: -
  可见,整数通过一个正则表达式来定义。

  语法通常以一种被称作BNF的格式来定义,我们的语言将会被定义成:

  expression :=  term  operation  term

  operation :=  PLUS | MINUS

  term := INTEGER | expression

  我们说如果一种语言如果它的语法是上下文无关文法,则可以通过解析器来解析。对于上下文无关文法的一个直观的定义是该文法能够用BNF来完整的表达。正式的定义可查阅http://en.wikipedia.org/wiki/Context-free_grammar

  解析类型

  有两种基础的解析器类型—自顶向下解析器和自底向上解析器。比较直观的解释是,自顶向下解析器是查看句法的最高层结构,然后尝试匹配其中一个,自底向上解析器从输入开始,然后逐步转换为句法规则,从底层规则开始直到匹配最高层规则。

  我们来看一下这两种类型的解析器是如何解析我们的例子的:

  自顶向上解析器从最高层规则开始—它将“2+3”作为一个表达式,然后识别“2+3-1”为一个表达式。

  自底向上解析器将扫描输入直到匹配一条规则,然后用该规则取代匹配的输入,直到解析完所有输入。有一部分匹配的表达式被放在解析堆栈中。

  

  
这种自底向上的类型被称为转换减少解析器,因为输入向右移动,并且逐渐简化为语法规则。

  自动化解析器

  有些工具可以产生一个解析器,它们被称为解析器生成器。你需要指定语言的语法—词汇表和句法规则,它就可以生成有一个解析器。创建一个解析器需要对解析有一个深入的理解,手动去创建一个性能优良的解析器是不容易的,因此解析器生成器是非常有用的。

  Webkit 使用了两个很著名的解析器生成器——用于创建语法分析器的Flex及创建解析器的BisonFlex的输入是一个包含了符号定义的正则表达式,Bison的输入是用BNF格式表示的语法规则。

  2、HTML解析器

  3、CSS解析

  4、处理脚本和样式表的顺序

四、构建渲染树

五、布局

六、备注

  本文是由一篇外国文章翻译而成,外文地址链接为http://taligarsiel.com/Projects/howbrowserswork1.htm#The_browsers_we_will_talk_about。后续待更新。



posted @ 2015-07-22 20:42  温布利往事  阅读(1808)  评论(6编辑  收藏  举报