前端必读:浏览器内部工作原理
英文原文:How Browsers Work: Behind the Scenes of Modern Web Browsers
一、介绍
浏览器可以被认为是使用最广泛的软件,本文将介绍浏览器的工作原理,
我们将看到,从你在地址栏输入 google.com 到你看到 google 主页过程中都发
生了什么。
将讨论的浏览器
今天,有五种主流浏览器——IE、Firefox、Safari、Chrome 及 Opera。
本文将基于一些开源浏览器的例子——Firefox、Chrome 及 Safari,
Safari 是部分开源的。
根据 W3C(World Wide Web Consortium 万维网联盟)的浏览器统计数据,
当前(2011 年 5 月),Firefox、Safari 及 Chrome 的市场占有率综合已接近
60%。(原文为 2009 年 10 月,数据没有太大变化)因此,可以说开源浏览器
已经占据了浏览器市场的半壁江山。
浏览器的主要功能
浏览器的主要功能是将用户选择的 web 资源呈现出来,它需要从服务器请
求资源,并将其显示在浏览器窗口中,资源的格式通常是 HTML,也包括 PDF、
image 及其他格式。用户用 URI(Uniform Resource Identifier 统一资源标识
符)来指定所请求资源的位置,在网络一章有更多讨论。
HTML 和 CSS 规范中规定了浏览器解释 html 文档的方式,由 W3C 组织对这
些规范进行维护,W3C 是负责制定 web 标准的组织。
HTML 规范的最新版本是 HTML4(http://www.w3.org/TR/html401/),HTML5
还在制定中(译注:两年 前),最新的 CSS 规范版本是 2
(http://www.w3.org/TR/CSS2),CSS3 也还正在制定中(译注:同样两年
前)。
这些年来,浏览器厂商纷纷开发自己的扩展,对规范的遵循并不完善,这
为 web 开发者带来了严重的兼容性问题。
但是,浏览器的用户界面则差不多,常见的用户界面元素包括:
用来输入 URI 的地址栏
前进、后退按钮
书签选项
用于刷新及暂停当前加载文档的刷新、暂停按钮
用于到达主页的主页按钮
奇怪的是,并没有哪个正式公布的规范对用户界面做出规定,这些是多年
来各浏览器厂商之间相互模仿和不断改进的结果。
HTML5 并没有规定浏览器必须具有的 UI 元素,但列出了一些常用元素,包
括地址栏、状态栏及工具栏。还有一些浏览器有自己专有的功能,比如
Firefox 的下载管理。更多相关内容将在后面讨论用户界面时介绍。
浏览器的主要构成(High Level Structure)
浏览器的主要组件包括:
1. 用户界面 - 包括地址栏、后退/前进按钮、书签目录等,也就是你所
看到的除了用来显示你所请求页面的主窗口之外的其他部分。
2. 浏览器引擎 - 用来查询及操作渲染引擎的接口。
3. 渲染引擎 - 用来显示请求的内容,例如,如果请求内容为 html,它
负责解析 html 及 css,并将解析后的结果显示出来。
4. 网络 - 用来完成网络调用,例如 http 请求,它具有平台无关的接
口,可以在不同平台上工作。
5. UI 后端 - 用来绘制类似组合选择框及对话框等基本组件,具有不特
定于某个平台的通用接口,底层使用操作系统的用户接口。
6. JS 解释器 - 用来解释执行 JS 代码。
7. 数据存储 - 属于持久层,浏览器需要在硬盘中保存类似 cookie 的各
种数据,HTML5 定义了 web database 技术,这是一种轻量级完整的客户端存储
技术
图 1:浏览器主要组件
需要注意的是,不同于大部分浏览器,Chrome 为每个 Tab 分配了各自的渲
染引擎实例,每个 Tab 就是一个独立的进程。
对于构成浏览器的这些组件,后面会逐一详细讨论。
二、渲染引擎(The rendering
engine)
渲染引擎的职责就是渲染,即在浏览器窗口中显示所请求的内容。
默认情况下,渲染引擎可以显示 html、xml 文档及图片,它也可以借助插
件(一种浏览器扩展)显示其他类型数据,例如使用 PDF 阅读器插件, 可以显
示 PDF 格式,将由专门一章讲解插件及扩展,这里只讨论渲染引擎最主要的用
途——显示应用了 CSS 之后的 html 及图片。
渲染引擎简介
本文所讨论的浏览器——Firefox、Chrome 和 Safari 是基于两种渲染引擎
构建的,Firefox 使用 Geoko——Mozilla 自主研发的渲染引擎,Safari 和
Chrome 都使用 webkit。
Webkit 是一款开源渲染引擎,它本来是为 Linux 平台研发的,后来由
Apple 移植到 Mac 及 Windows 上,相关内容请参考 http://webkit.org。
渲染主流程(The main flow)
渲染引擎首先通过网络获得所请求文档的内容,通常以 8K 分块的方式完
成。
下面是渲染引擎在取得内容之后的基本流程:
解析 html 以构建 dom 树 -> 构建 render 树 -> 布局 render 树 -> 绘制
render 树
图 2:渲染引擎基本流程
渲染引擎开始解析 html,并将标签转化为内容树中的 dom 节点。接着,它
解析外部 CSS 文件及 style 标签中的样式信息。这些样式信息以及 html 中的可
见性指令将被用来构建另一棵树——render 树。
Render 树由一些包含有颜色和大小等属性的矩形组成,它们将被按照正确
的顺序显示到屏幕上。
Render 树构建好了之后,将会执行布局过程,它将确定每个节点在屏幕上
的确切坐标。再下一步就是绘制,即遍历 render 树,并使用 UI 后端层绘制每
个节点。
值得注意的是,这个过程是逐步完成的,为了更好的用户体验,渲染引擎
将会尽可能早的将内容呈现到屏幕上,并不会等到所有的 html 都解析完成之后
再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,
可能还在通过网络下载其余内容。
图 3:webkit 主流程
图 4:Mozilla 的 Geoko 渲染引擎主流程
从图 3 和 4 中可以看出,尽管 webkit 和 Gecko 使用的术语稍有不同,他们
的主要流程基本相同。Gecko 称可见的格式化元素组成的树为 frame 树,每个
元素都是一个 frame,webkit 则使用 render 树这个名词来命名由渲染对象组成
的树。Webkit 中元素的定位称为布局,而 Gecko 中称为回流。Webkit 称利用
dom 节点及样式信息去构建 render 树的过程为 attachment,Gecko 在 html 和
dom 树之间 附加了一层,这层称为内容接收器,相当制造 dom 元素的工厂。下
面将讨论流程中的各个阶段。
三、解析与 DOM 树构建(Parsing and DOM tree construction)
解析(Parsing-general)
既然解析是渲染引擎中一个非常重要的过程,我们将稍微深入的研究它。
首先简要介绍一下解析。
解析一个文档即将其转换为具有一定意义的结构——编码可以理解和使用
的东西。解析的结果通常是表达文档结构的节点树,称为解析树或语法树。
例如,解析“2+3-1”这个表达式,可能返回这样一棵树。
图 5:数学表达式树节点
文法(Grammars)
解析基于文档依据的语法规则——文档的语言或格式。每种可被解析的格
式必须具有由词汇及语法规则组成的特定的文法,称为上下文无关文法。人类
语言不具有这一特性,因此不能被一般的解析技术所解析。
解析器-词法分析器(Parser-Lexer combination)
解析可以分为两个子过程——语法分析及词法分析
词法分析就是将输入分解为符号,符号是语言的词汇表——基本有效单元
的集合。对于人类语言来说,它相当于我们字典中出现的所有单词。
语法分析指对语言应用语法规则。
解析器一般将工作分配给两个组件——词法分析器(有时也叫分词器)负
责将输入分解为合法的符号,解析器则根据语言的语法规则分析文档结构,从
而构建解析树,词法分析器知道怎么跳过空白和换行之类的无关字符。
图 6:从源文档到解析树
解析过程是迭代的,解析器从词法分析器处取到一个新的符号,并试着用
这个符号匹配一条语法规则,如果匹配了一条规则,这个符号对应的节点将被
添 加到解析树上,然后解析器请求另一个符号。如果没有匹配到规则,解析器
将在内部保存该符号,并从词法分析器取下一个符号,直到所有内部保存的符
号能够匹配 一项语法规则。如果最终没有找到匹配的规则,解析器将抛出一个
异常,这意味着文档无效或是包含语法错误。
转换(Translation)
很多时候,解析树并不是最终结果。解析一般在转换中使用——将输入文
档转换为另一种格式。编译就是个例子,编译器在将一段源码编译为机器码的
时候,先将源码解析为解析树,然后将该树转换为一个机器码文档。
图 7:编译流程
解析实例 Parsing example
图 5 中,我们从一个数学表达式构建了一个解析树,这里定义一个简单的
数学语言来看下解析过程。
词汇表:我们的语言包括整数、加号及减号。
语法:
1. 该语言的语法基本单元包括表达式、term 及操作符
2. 该语言可以包括多个表达式
3. 一个表达式定义为两个 term 通过一个操作符连接
4. 操作符可以是加号或减号
5. term 可以是一个整数或一个表达式
现在来分析一下“2+3-1”这个输入