翻译 | Web浏览器是如何运作的?

2020-10-253236

原文自博客发布平台medium,作者为 Bibek Shah,传送门

文外话:想想自己已经有快3个月没搞翻译文章了,实在可耻。当然也不能把原因放到说自己很忙上,最大原因就是自己变懒了。

之后的节奏可能会放慢,我会尽量挑选些有趣、有用的文章来做个简单的翻译,如果各位读者能从中得到些知识,那就最好了。

Web浏览器大概是现在人们用来访问互联网中最常使用的方式了。从web浏览器的一系列进化史可以看出,有许许多多的传统“胖客户端”已经被浏览器所取代,从而提高了它自身的可用性和普遍性。web浏览器是一种提供web服务器的访问、向 URL 发送网络请求、获取资源并且以交互的方式表现出来。当今比较普遍的浏览器有火狐、Chrome、Safari、IE 和 Opera。

浏览器的构造

1. 用户界面

它是指一个通过浏览器中的组件来完成用户和应用之间的交互的空间。外界上并没有对Web浏览器的外观作出一个特定的标准。HTML5规范上也没有定义 UI 元素,而是列出了一些常用的元素:位置栏、滚动栏、状态栏和工具栏。

2. 浏览器引擎

浏览器在 UI 和底层下的渲染引擎之间添加了一种高级接口。这个接口会发起一个查询并且根据用户的交互操作来操纵渲染引擎。这个接口还提供一个方法来初始化加载URL,并且负责重新加载、后退、前进等浏览器操作。

3. 渲染引擎

渲染引擎是负责将网页上的内容展示在屏幕前。渲染引擎最重要的一个操作是解析 HTML。默认情况下,它可以展示 HTML、XML、图像以及经由插件或者扩展的支持的其他类型文件。

渲染引擎的流程

现代浏览器的渲染引擎

  • 火狐:Gecko Software
  • Safari:WebKit
  • Chrome、Opera:Blink
  • Internet Explorer:Trident

关键渲染路径

在第一次的时候,为了在屏幕上绘制像素,浏览器从网络接收到 HTML、CSS、JS 等数据后,必须经过一系列名为“关键渲染路径”的过程。这其中包括 DOM、CSSOM、渲染树、布局和绘制。

从数据到 DOM

来自网络层的请求内容以 8kb 每块的二进制流格式传输到到渲染引擎当中。然后这些原始字节根据字符编码被转换为 HTML 文件的一个个字符

接着字符被转换为令牌(tokens)。Lexer(词法分析器) 执行词法分析,将输入内容解构为令牌。在令牌化期间,文件中的每一个开始和结束标记都会被解析。Lexer 知道如何去去除不相关的字符串,例如空格和换行符。然后,解析器开始进行语法分析,使用语言的语法规则,通过分析文档结构,来构造解析树

这个分析过程是迭代进行的。 它会要求 Lexer 提供新的令牌,并且如果语言语法规则匹配的话,这个令牌会被添加到解析树当中。如果没有匹配到规则,解析器会在内部将令牌存储起来,并且会不断要求新的令牌,直到找到匹配内部所有令牌的规则为止。如果没有找到任何的规则,解析器将会抛出异常。这意味着文档是无效的,并且包含语法错误。

这些链接在树数据结构节点被称为 DOM文档对象模型)。这些节点间存有父子、相邻同级的关系。

DOM 树

从 CSS 数据到 CSSOM

接着,CSS 数据的原始字节会被转换成字符令牌节点,并且最终组合成 CSSOM(CSS 对象模型)。在 CSS 中具有一个叫做级联的块,是用于决定元素所使用的样式。元素的样式数据,可以继承自父元素,也可以是元素本身。浏览器需要对 CSS 树进行递归查询,以此来确认特定元素的样式。

CSS 树

从 DOM 和 CSSOM 到渲染树

DOM 树中包含有关 HTML 元素的关系信息,而 CSSOM 树则包含元素的样式信息。浏览器从根节点开始遍历每个可视节点。有些节点通过 CSS 控制被隐藏起来并且不反馈到渲染输出当中。对于每一个可视节点,浏览器与 CSSOM 中定义的符合条件的规则相匹配,最终这些节点和它们各自的内容及样式组合成了名为渲染树布局树)的结构。

渲染树

布局

然后,到了下一步的处理,名为布局。每个内容的确切大小和位置在渲染到页面(浏览器视口)之前应当被计算清楚。这个过程也被称为回流(reflow)。HTML 使用基于流的布局模型,这意味着几何体在多数时候都是单独地去计算的。这个过程从文档的根目录开始,它是递归执行的。

绘制

遍历每一个渲染器,并且调用绘制方法来将内容展示到屏幕前。绘制的过程可以是全局的(绘制整个树),或者是增量的(渲染树绘制矩形)并且操作系统在特定节点上执行绘制事件而不会影响整个树。绘制是一个渐进的过程,在这个过程中,某些部分节点被解析和渲染,而其余部分的网络请求过程也在同时执行。

4. JavaScript 解析器(JS 引擎)

JavaScript 是一种脚本语言,它允许你动态更新 web 内容、通过浏览器的 JS 引擎控制多媒体和动态图像文件。DOM 和 CSSOM 为 JS 提供一个接口,用于修改 DOM 和 CSSOM。浏览器由于不清楚特定的 JS 会进行什么处理,所以在遇到 script 标签的时候,都会暂停 DOM 树的解析。每一个 script 都会阻止 DOM 树的构建。

在从服务端中反馈信息到 JS 解析器后,JS 引擎开始进行代码的分析。引擎会将代码转换为机器能理解的对象。这些存储所有在以树表现层的抽象语法结构的解析器信息被称为对象语法树(AST)。这些对象被输入到解析器当中,并且将被转换为字节代码。

这些都是及时(JITs)编辑器,也就是说从服务端下载回来的 JavaScript 文件在客户端中会被实时编译。解析器和编译器是组合在一起的,解析器会立即进行源代码的解析执行,而编译器也会在客户端执行的过程中立即进行机器代码的编译。

不同的浏览器使用不同的 JS 引擎

  • chrome:V8(JavaScript 引擎)(Node JS 是以此搭建的)
  • Mozilla:SpriderMonkey(过去被称为“squirrel Fish”)
  • Microsoft Edge:Chakra
  • Safari:JavaScriptCore / Nitro WebKit

5. UI 后端

它是用于绘制像组合框或者窗口等基本的小部件。在底层,它是使用操作系统的用户界面方法。这个模块提供了一个非特定的通用平台。

6. 数据存储

这一层是持久化的,它用于帮助浏览器存储数据信息(例如 cookies、会话信息、索引数据库、web SQL、书签、选项信息等)。新的 HTML5 规范表明了在 web 浏览器中数据库是完整的。

7. 网络

这是负责处理浏览器中的所有网络通信。在从请求 URL 中获取资源的时候,会使用到一系列通信协议,诸如 HTTP、HTTPs、FTP等。

web 浏览器在解析 URL 时依赖于 DNS。这些 DNS 记录会缓存在浏览器、操作系统、路由器或者 ISP 中。如果请求的 URL 不在缓存中,ISP 的 DNS 服务器将发起 DNS 查询来查找请求服务器的 IP。在接收到正确的 IP 地址后,浏览器通过协议来向服务器发起连接。浏览器会发送 SYN(同步)数据包到服务器中,询问是否为 TCP 连接打开。同意建立后,服务器会使用 SYN/ACK 数据包对 SYN 数据包的 ACK 作出响应。

浏览器在接收到服务器的 SYN/ACK 包后,会对其发送 ACK 包作为响应。这时候 TCP 连接已经被创建好了并作为数据传输所使用。建立连接后,数据就准备好被传输了。要正确的传输数据,连接必须满足 HTTP 协议中关于连接、消息传递、连接和响应规则的定义。

阻塞渲染和阻塞解析资源

每当浏览器遇到需要外部加载的 CSS 文件时,都会通过网络发送异步请求来获取对应的 .css 文件。在每一个下载完后,会立刻进行对其元素的解析和不会阻断 DOM 的构造,而不需要等待其他 CSS 资源的下载。然而,即使 DOM 树构造完成后,如果 CSSOM 还没准备好的话,也不会有任何内容被渲染到浏览器的屏幕中为了完成渲染,DOM 和 CSSOM 都需要被构建好。因此,HTML 和 CSS 彼此对彼此都是阻塞渲染资源。渲染未完全加载的 CSS 内容会导致样式闪烁(FOUC)

阻塞渲染 CSS(同时加载)

脚本中的延迟和异步

延迟属性和异步属性都能帮助开发者去指定 JavaScript 在执行过程中的异步模式。

推测解析(Speculative Parsing)

正如我们所看到的,当 script 被执行时,解析都会被暂停。这会在加载其他资源时出现延迟。在 2008 年,微软推出了一个预加载的概念名为“先行下载器”(lookahead downloader)。随后是 Firefox、Chrome 和 Safari 相继推出相同理念不同名称的技术。Chrome 和 Safari 的名为 “预加载扫描器”(preload scanner),而 Firefox 的名为 “推测解析器”(speculative parser)。

这个技术的基本思想是将发现需要加载的文件添加到一个列表中,并且在后台并行下载。到脚本完成执行后,文件就已经下载完成可以使用了,然后下一个轻量级的解析器会扫描剩余的标记来寻找其他需要的资源。在除了火狐的其他的浏览器中,资源都是预加载的。而在火狐(在版本4后)中,它会提前创建一个预测的 DOM 树。如果预测成功,浏览器就不需要重新分析 DOM 的文件结构了。但缺点是,如果预测失败,将会执行更多的工作。

为什么在不同的浏览器中,相同的网站会看上去不同?

许多原因导致这个事情的发生。由于在不同的浏览器中,它们使用的是不同的浏览器引擎(渲染引擎和 JavaScript 引擎),它们以略微不同的方式去解析源代码,最后导致差异的产生。同样地,因为浏览器之间的默认设置不同,默认设置下的网页的样式也会有所不同。

造成这种差异的其他原因也包括计算机的设置(屏幕分配率、颜色平衡、操作系统差异、字体)、引擎和页面的 bug 等。

浏览器的比较

今天市场上有各种各样的浏览器。尽管它们使用的主程序是相通的,但是在多个方面它们又有很多不同。形成差距的领域有平台(Linux、Windows、Mac、BSD 和其他 Unix 平台)、协议、图形用户界面(Real、Headless)、HTML5、是否开源等。详细的介绍可以从这里获取到。

祝你冲浪快乐!!!

这篇文章中,从浏览器的结构出发,从用户界面、浏览器引擎、渲染引擎、解析器等多个角度去说明浏览器的工作流程。

之前有一个同行的朋友跟我说过,在后端面试中,阿里的面试官会问到浏览器是如何工作的。可想而知,要作为一个 web 工程师,了解的东西,除了特定的专业领域知识和技术外,还需要对整个大环境的知识有所深入。不能因为说我是学习后端的,所以前端的我不需要清楚,反之亦然。

而了解浏览器的工作流程,也能更好地从细微的角度去了解 web 开发,毕竟浏览器是作为互联网中必不可少的客户端之一。所以我希望这篇文章,能对各位开发工程师能够有所帮助。

分享
点赞1
打赏
上一篇:Docker常用命令笔记(一)
下一篇:使用redis实现分布式锁