felix-cao / Blog

A little progress a day makes you a big success!
31 stars 4 forks source link

浏览器工作原理详解 #128

Open felix-cao opened 5 years ago

felix-cao commented 5 years ago

本文转自 《浏览器工作原理详解》

这篇文章是以色列开发人员塔利·加希尔的研究成果。她在查阅了所有公开发布的关于浏览器内部机制的数据,并花了很多时间来研读网络浏览器的源代码。她写道:

在 IE 占据 90%市场份额的年代,我们除了把浏览器当成一个“黑箱”,什么也做不了。但是现在,开放源代码的浏览器拥有了过半的市场份额,因此,是时候来揭开神秘的面纱,一探网络浏览器的内幕了。呃,里面只有数以百万行计的C++ 代码…

本篇文章的英文原版:How Browsers Work: Behind the Scenes of Modern Web Browsers。 本文主要参考和更新自下面两篇译文: 1)前端必读:浏览器内部工作原理 2)前端文摘:深入解析浏览器的幕后工作原理

作为一名网络开发人员,学习浏览器的内部工作原理将有助于您作出更明智的决策,并理解那些最佳开发实践的个中缘由。尽管这是一篇相当长的文档,但是我们建议您花些时间来仔细阅读;读完之后,您肯定会觉得所费不虚。 保罗·爱丽诗(Paul Irish),Chrome 浏览器开发人员事务部

第一章、 简介

浏览器是使用最广的软件之一。在这篇博文中,我将介绍浏览器的幕后工作原理。通过阅读本文,我们将会了解,从您在地址栏输入 google.com ,直到您在浏览器屏幕上看到 Google 首页的整个过程中都发生了些什么。

1.1、讨论的浏览器

目前使用的主流浏览器有五个:Internet ExplorerFirefoxSafariChromeOpera浏览器。本文主要以开源浏览器为主进行分析,即 FirefoxChromeSafari(部分开源)。根据 StatCounter 浏览器统计数据,目前(2016年 2 月)Firefox(14.67%)、Safari(9.46%) 和 Chrome(55.33%) 浏览器的总市场占有率将近 80%(这个数字在2011年8月的时候,才将近60%)。由此可见,如今开源浏览器在浏览器市场中占据绝大多数的市场份额。

1.2、 浏览器的主要功能

  浏览器的主要功能就是向服务器发出请求,在浏览器窗口中展示您想要访问的网络资源。这里所说的资源一般是指 HTML 文档,也可以是 PDF、图片或其他的类型。资源的位置由用户使用 URI(统一资源标示符)指定。

  浏览器解释并显示HTML文件的方式是在 HTMLCSS 规范中指定的。这些规范由网络标准化组织 W3C(万维网联盟)进行维护。多年以来,各浏览器都没有完全遵从这些规范,同时还在开发自己独有的扩展程序,这给网络开发人员带来了严重的兼容性问题。如今,大多数的浏览器都开始尽量遵从规范。

  浏览器的用户界面有很多彼此相同的元素,其中包括:用来输入 URI 的地址栏;前进和后退按钮;书签设置选项;用于刷新和停止加载当前文档的刷新和停止按钮;用于返回主页的主页按钮。   奇怪的是,浏览器的用户界面并没有任何正式的规范,这是多年来的最佳实践自然发展以及彼此模仿的结果。HTML5 也没有定义浏览器必须具有的用户界面元素,但列出了一些通用的元素,例如地址栏、状态栏和工具栏等。当然,各浏览器也可以有自己独特的功能,比如 Firefox 的下载管理器。

1.3、 浏览器的高层结构(High Level Structure)

浏览器的主要组件包括:

图1.1:浏览器的主要组件。

值得注意的是,不同于大多数浏览器,Chrome 浏览器为每个标签页(Tab)都分配了各自的渲染引擎实例,每个标签页都是一个独立的进程(即每个标签页面都在独立的“沙箱”内运行,在提高安全性的同时,一个标签页面的崩溃也不会导致其他标签页面被关闭)。 对于构成浏览器的这些组件,后面会逐一详细讨论。

第二章、 渲染引擎(The rendering engine)

浏览器有个叫渲染引擎的组件, 负责显示请求的内容。如果请求的内容是 HTML,它就负责解析 HTMLCSS 内容,并将解析后的内容显示在屏幕上。

渲染引擎的职责就是渲染,即在浏览器窗口中显示所请求的内容。这是每一个浏览器的核心部分,所以渲染引擎也称为浏览器内核。

默认情况下,渲染引擎只可显示 HTMLXML 文档及图片。不过通过插件(或浏览器扩展程序),浏览器渲染引擎也可以显示其它类型的内容。例如,使用 PDF 查看器插件就能显示 PDF 文档。

2.1、渲染引擎简介

当前流行的FirefoxChromeSafari浏览器是基于两种渲染引擎构建的。Firefox 使用的是 Gecko,这是 Mozilla 公司“自制”的渲染引擎。而 SafariChrome(28版本以前)浏览器使用的都是 Webkit

2013年7月10日发布的 Chrome 28 版本中,Chrome 浏览器开始正式使用 Blink 内核。所以,Webkit 已经成为了 Chrome 浏览器的前内核。

Webkit 是一种开放源代码渲染引擎,起初用于 Linux 平台,随后由 Apple 公司进行修改,从而支持苹果机和 Windows。有关详情,请参阅 webkit.org

2.2、主流程(The main flow)

渲染引擎获取了文档内容之后,渲染引擎开始正式工作,如下图渲染引擎的基本流程:

值得注意的是,这个过程是逐步完成的,为了更好的用户体验,渲染引擎将会尽可能早的将内容呈现到屏幕上,并不会等到所有的 html 都解析完成之后再去构建和布局 render 树。它是解析完一部分内容就显示一部分内容,同时,可能还在通过网络下载其余内容。

图2.2为Webkit 主流程

图2.3为 MozillaGecko 渲染引擎主流程

从图2.2 和图2.3可以看出,虽然 WebkitGecko 使用的术语略有不同,但整体流程还是基本相同的。

第三章、 解析与DOM树构建(Parsing and DOM tree construction)

3.1、 解析(Parsing-general)

既然解析是渲染引擎中一个非常重要的过程,我们将稍微深入的研究它。首先明白什么叫做解(parsing)。 解析一个文档就是指将这个文档翻译成一个可以让代码理解和使用的有意义的结构。得到的结构通常是一个代表了该文档结构的节点树,通常称之为解析树或语法树。

例如, 解析“2+3-1”这个表达式,可能返回这样一棵树。 image 图3.1:数学表达式树节点

1、文法(Grammars) 解析是以文档所遵循的语法规则(编写文档所用的语言或格式)为基础的。所有可以解析的格式都必须对应确定的语法(由词汇和语法规则构成)。这称为与上下文无关的文法。人类语言并不属于这样的语言,因此无法用常规的解析技术进行解析。

2、解析器-词法分析器(Parser-Lexer combination)

解析一般可分为两个子过程:语法分析和词法分析。

解析工作一般由两个组件共同完成:

解析是一个迭代的过程。通常,解析器会向词法分析器请求一个新标记,并尝试将其与某条语法规则进行匹配。如果发现了匹配规则,解析器会将一个对应于该标记的节点添加到解析树中,然后继续请求下一个标记。 如果没有规则与该标记匹配,解析器就会将标记存储到内部,并继续请求下一个标记,直至找到可与所有内部存储的标记匹配的规则。 如果没有规则(即没有找到相应的语法规则),解析器就会引发一个异常。这意味着文档无效,包含语法错误。

3、转换(Translation)

很多时候,解析树还不是最终结果。解析通常是在转换过程中使用的,而转换是指将输入文档转换成另一种格式。编译就是一个例子。编译器可将源代码编译成机器代码,具体过程是首先将源代码解析成解析树,然后将解析树翻译成机器代码文档。

image 图3.3:编译流程

4、解析示例(Parsing example)

在图3.1中,我们通过一个数学表达式建立了解析树。现在,让我们试着定义一个简单的数学语言,用来演示解析的过程。

现在来分析一下”2+3-1”这个输入。 匹配语法规则的第一个子串是2,而根据第5条语法规则,这是一个项。匹配语法规则的第二个子串是 2 + 3,而根据第 3 条规则(一个项接一个运算符,然后再接一个项),这是一个表达式。下一个匹配项已经到了输入的结束。2 + 3 - 1 是一个表达式,因为我们已经知道 2 + 3 是一个项,这样就符合“一个项接一个运算符,然后再接一个项”的规则。2 + +不与任何规则匹配,因此是无效的输入。

5、词汇和语法的正式定义

1)、词汇通常用正则表达式表示。

例如,我们的示例语言可以定义如下:

INTEGER :0|[1-9][0-9]*
PLUS : +
MINUS: -

正如您所看到的,这里用正则表达式给出了整数的定义。

2)、语法通常使用一种称为 BNF 的格式来定义。

我们的示例语言可以定义如下:

expression :=  term  operation  term
operation :=  PLUS | MINUS
term := INTEGER | expression

之前我们说过,如果语言的语法是与上下文无关的语法,就可以由常规解析器进行解析。

与上下文无关的语法的直观定义就是可以完全用BNF格式表达的语法。有关正式定义,请参阅关于与上下文无关的语法的维基百科文章。

6、解析器类型

有两种基本类型的解析器:自上而下解析器和自下而上解析器。直观地来说,自上而下的解析器从语法的高层结构出发,尝试从中找到匹配的结构。而自下而上的解析器从低层规则出发,将输入内容逐步转化为语法规则,直至满足高层规则。

让我们来看看这两种解析器会如何解析我们的示例: 自顶向下解析器从最高层规则开始——它先识别出”2+3”,将其视为一个表达式,然后识别出”2+3-1”为一个表达式(识别表达式的过程中匹配了其他规则,但起点是最高层规则)。

自下而上的解析器将扫描输入内容,找到匹配的规则后,将匹配的输入内容替换成规则。如此继续替换,直到输入内容的结尾。部分匹配的表达式保存在解析器的堆栈中。

To Be Continuing