首页 > 代码库 > 浏览器工作原理及相关内核、技术介绍
浏览器工作原理及相关内核、技术介绍
正文开始:
一、浏览器工作原理(简化版)
1、浏览器用来干什么用
浏览器的主要功能是将用户请求访问的web资源呈现出来,它需要从服务器请求资源,并将其显示在浏览器窗口中,资源的格式通常是HTML,也包括PDF、image及其他格式。用户用URI(Uniform Resource Identifier 统一资源标识符)来指定所请求资源的位置。 HTML和CSS规范中规定了浏览器解释html文档的方式,由W3C组织对这些规范进行维护,W3C是负责制定web标准的组织。
2、浏览器的主要构成组件
直接上图:
- 用户界面- 包括地址栏、后退/前进按钮、书签目录等,也就是你所看到的除了用来显示你所请求页面的主窗口之外的其他部分
- 浏览器引擎- 用来查询及操作渲染引擎的接口
- 渲染引擎- 用来显示请求的内容,例如,如果请求内容为html,它负责解析html及css,并将解析后的结果显示出来
- 网络- 用来完成网络调用,例如http请求,它具有平台无关的接口,可以在不同平台上工作
- UI后端- 用来绘制类似组合选择框及对话框等基本组件,具有不特定于某个平台的通用接口,底层使用操作系统的用户接口
- JS解释器- 用来解释执行JS代码
- 数据存储- 属于持久层,浏览器需要在硬盘中保存类似cookie的各种数据,HTML5定义了web database技术,同样是一种轻量级完整的客户端存储技术
3、数据渲染(The rendering engine)
网页浏览器的页面渲染引擎也被称为排版引擎,它负责取得网页的内容(HTML、XML、图象等等)、整理信息(例如加入CSS等),以及计算网页的显示方式然后会输出至显示器或打印机。所有网页浏览器、电子邮件客户端以及其它需要编辑、显示网络内容的应用程序都需要排版引擎。
Firefox使用Gecko——Mozilla自主研发的渲染引擎,Safari和Chrome都使用webkit。Webkit是一款开源渲染引擎,它本来是为linux平台研发的,后来由Apple移植到Mac及Windows上,相关内容请参考http://webkit.org。
4、数据渲染流程(The main flow)
渲染引擎开始解析html,并将标签转化为内容树中的dom节点。接着,它解析外部CSS文件及style标签中的样式信息。这些样式信息以及html中的可见性指令将被用来构建另一棵树——render树。 Render树由一些包含有颜色和大小等属性的矩形组成,它们将被按照正确的顺序显示到屏幕上。 Render树构建好了之后,将会执行布局过程,它将确定每个节点在屏幕上的确切坐标。再下一步就是绘制,即遍历render树,并使用UI后端层绘制每个节点。
值得注意的是,这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的html都解析完成之后再去构建和布局render树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。
5、DOM
输出的树,也就是解析树,是由DOM元素及属性节点组成的。DOM是文档对象模型的缩写,它是html文档的对象表示,作为html元素的外部接口供js等调用。 树的根是“document”对象。 DOM和标签基本是一一对应的关系,例如,如下的标签:
<html> < body> < p<Hello DOM</p> < div><img src=http://www.mamicode.com/”example.png” />
解析完后的DOM树为:
6、解析算法(The parsing algorithm)
hmtl不能被一般的自顶向下或自底向上的解析器所解析。 原因是: 1. 这门语言本身的宽容特性 2. 浏览器对一些常见的非法html有容错机制 3. 解析过程是往复的,通常源码不会在解析过程中发生改变,但在html中,脚本标签包含的“document.write”可能添加标签,这说明在解析过程中实际上修改了输入不能使用正则解析技术,浏览器为html定制了专属的解析器。
Html5规范中描述了这个解析算法,算法包括两个阶段——符号化及构建树。 符号化是词法分析的过程,将输入解析为符号,html的符号包括开始标签、结束标签、属性名及属性值。 符号识别器识别出符号后,将其传递给树构建器,并读取下一个字符,以识别下一个符号,这样直到处理完所有输入。
7、树的构建算法(Tree construction algorithm)
在树的构建阶段,将修改以Document为根的DOM树,将元素附加到树上。每个由符号识别器识别生成的节点将会被树构造器进行处理,规范中定义了每个符号相对应的Dom元素,对应的Dom元素将会被创建。这些元素除了会被添加到Dom树上,还将被添加到开放元素堆栈中。这个堆栈用来纠正嵌套的未匹配和未闭合标签,这个算法也是用状态机来描述,所有的状态采用插入模式。
来看一下示例中树的创建过程:
<html> < body> Hello world < /body> < /html>
构建树这一阶段的输入是符号识别阶段生成的符号序列。 首先是“initial mode”,接收到html符号后将转换为“before html”模式,在这个模式中对这个符号进行再处理。此时,创建了一个HTMLHtmlElement元素,并将其附加到根Document对象上。 状态此时变为“before head”,接收到body符号时,即使这里没有head符号,也将自动创建一个HTMLHeadElement元素并附加到树上。 现在,转到“in head”模式,然后是“after head”。到这里,body符号会被再次处理,将创建一个HTMLBodyElement并插入到树中,同时,转移到“in body”模式。 然后,接收到字符串“Hello world”的字符符号,第一个字符将导致创建并插入一个text节点,其他字符将附加到该节点。 接收到body结束符号时,转移到“after body”模式,接着接收到html结束符号,这个符号意味着转移到了“after after body”模式,当接收到文件结束符时,整个解析过程结束。
8、渲染树的构造(Render tree construction)
当Dom树构建完成时,浏览器开始构建另一棵树——渲染树。渲染树由元素显示序列中的可见元素组成,它是文档的可视化表示,构建这棵树是为了以正确的顺序绘制文档内容。 Firefox将渲染树中的元素称为frames,webkit则用renderer或渲染对象来描述这些元素。
一个渲染对象知道如何布局以及绘制自己和它的children。 RenderObject是Webkit的渲染对象基类,它的定义如下:
class RenderObject{ virtual void layout(); virtual void paint(PaintInfo); virtual void rect repaintRect(); Node* node; //the DOM node RenderStyle* style; // the computed style RenderLayer* containgLayer; //the containing z-index layer } 每个渲染对象用一个和该节点的css盒模型相对应的矩形区域来表示,正如css2所描述的那样,它包含诸如宽、高和位置之类的几何信息。盒模型的类型受该节点相关的display样式属性的影响(参考样式计算章节)。下面的webkit代码说明了如何根据display属性决定某个节点创建何种类型的渲染对象。
RenderObject* RenderObject::createObject(Node* node, RenderStyle* style) { Document* doc = node->document(); RenderArena* arena = doc->renderArena(); … RenderObject* o = 0; switch (style->display()) { case NONE: break; case INLINE: o = new (arena) RenderInline(node); break; case BLOCK: o = new (arena) RenderBlock(node); break; case INLINE_BLOCK: o = new (arena) RenderBlock(node); break; case LIST_ITEM: o = new (arena) RenderListItem(node); break; … } return o; } 元素的类型也需要考虑,例如,表单控件和表格带有特殊的框架。 在webkit中,如果一个元素想创建一个特殊的渲染对象,它需要复写“createRenderer”方法,使渲染对象指向不包含几何信息的样式对象。
9、样式计算(Style Computation)
创建渲染树需要计算出每个渲染对象的可视属性,这可以通过计算每个元素的样式属性得到。
样式包括各种来源的样式表,行内样式元素及html中的可视化属性(例如bgcolor),可视化属性转化为css样式属性。
样式表来源于浏览器默认样式表,及页面作者和用户提供的样式表——有些样式是浏览器用户提供的(浏览器允许用户定义喜欢的样式,例如,在Firefox中,可以通过在Firefox Profile目录下放置样式表实现)。 计算样式的一些困难:
样式数据是非常大的结构,保存大量的样式属性会带来内存问题。 如果不进行优化,找到每个元素匹配的规则会导致性能问题,为每个元素查找匹配的规则都需要遍历整个规则表,这个过程有很大的工作量。选择符可能有复杂的结构,匹配过程如果沿着一条开始看似正确,后来却被证明是无用的路径,则必须去尝试另一条路径。 例如,下面这个复杂选择符 div div div div{…}
这意味着规则应用到三个div的后代div元素,选择树上一条特定的路径去检查,这可能需要遍历节点树,最后却发现它只是两个div的后代,并不使用该规则,然后则需要沿着另一条路径去尝试
应用规则涉及非常复杂的级联,它们定义了规则的层次。
10、布局(Layout)
当渲染对象被创建并添加到树中,它们并没有位置和大小,计算这些值的过程称为layout或reflow。
Html使用基于流的布局模型,意味着大部分时间,可以以单一的途径进行几何计算。流中靠后的元素并不会影响前面元素的几何特性,所以布局可以在文档中从右向左、自上而下的进行。也存在一些例外,比如html tables。
坐标系统相对于根frame,使用top和left坐标。
布局是一个递归的过程,由根渲染对象开始,它对应html文档元素,布局继续递归的通过一些或所有的frame层级,为每个需要几何信息的渲染对象进行计算。 根渲染对象的位置是0,0,它的大小是viewport-浏览器窗口的可见部分。 所有的渲染对象都有一个layout或reflow方法,每个渲染对象调用需要布局的children的layout方法。
二、相关渲染引擎内核介绍
1、Gecko:Mozilla Firefox
标准支持:
- HTML 4.01 (支持部分HTML 5)
- XML 1.0
- XHTML 1.1
- MathML
- CSS Level 2.1(支持部份CSS 3)
- DOM Level 1和2(支持部份DOM 3)
- RDF
- JavaScript 1.8(ECMAScript 3,支持部分ECMAScript 5)由SpiderMonkey实现
- E4X
- SVG(支持部份SVG 1.1)
- XSLT和XPath由TransforMiiX实现
- XForms(借由官方的扩展)
2、WebKit:Apple Safari及Google Chrome
WebCore WebCore是一个由WebKit专案所开发的布局(Layout)、渲染(Rendering)及HTML和SVG的DOM函式库,完整的程式码皆由GNU宽通用公共许可证所授权,WebKit框架包装了WebCore及JavaScriptCore,并提供一个Objective-C应用程序接口来接介由C++所开发的WebCore渲染引擎及JavaScriptCore脚本引擎,透过Cocoa API就可以在应用程式中很简单的使用这些元件。之后的版本同时包含了一个跨平台的C++抽象平台,并且提供各种API使用。 WebKit通过Acid2及Acid3的测试,包含完美像素的渲染(pixel-perfect rendering)以及没有任何时间及不顺的问题。
JavaScriptCore JavaScriptCore是一个在WebKit中提供JavaScript引擎的框架,而且在OS X作为其他内容的脚本引擎[10][66]。JavaScriptCore最初是为KDE的JavaScript引擎(KJS)函式库及PCRE正则表达式函式库,JavaScriptCore从KJS及PCRE复刻之后,已比原先进步了许多,有了新的特色以及极大的效能改进。
Drosera Drosera是一个JavaScript调试工具,它被包含在每日编译的WebKit版本内。
3、Trident:Internet Explorer
在Internet Explorer第七版中,微软对Trident排版引擎做了的重大的变动,除了加入新的技术之外,并增加对网页标准的支持。尽管这些变动已经在相当大的程度上落后了其它的排版引擎,如Gecko、WebCore、KHTML、Webkit及Presto。
以Trident为核心的浏览器 Avant Browser(前身为IeOpera) Maxthon(前身为MyIE3.2、MyIE2) GreenBrowser(前身亦为MyIE3.2) TouchNet Browser 腾讯TT GOSURF 世界之窗(TheWorld Browser) MiniIE Sleipnir MyIE(新版4.x为GreenBrowser作者发布,3.2及之前版本为Maxthon、GreenBrowser、iTreeSurf等浏览器的前身) iTreeSurf(LovelyTree,前身亦为MyIE3.2) (注:中国大陆的大部分浏览器都使用Trident 排版引擎)
浏览器工作原理及相关内核、技术介绍