《浏览器工作原理与实践-学习笔记》--宏观视角下的浏览器

965 阅读15分钟

1.1 | Chrome架构:仅仅打开了1个页面,为什么有4个进程?

  1. 什么是并行处理?

    计算机中的并行处理就是同一时刻处理多个任务。

  2. 进程和线程。

  • 什么是进程?什么是线程?

    • 一个进程就是一个程序的运行实例。启动一个程序的时候,操作系统会为这个程序创建一块内存,用于存放代码、运行中的数据和一个执行任务的主线程,这样一个运行环境就叫做进程。
    • 线程是程序执行的最小单位。 线程是不能单独存在的,它是由进程来启动和管理的。
    • 线程是依附于进程的,而进程中使用多线程并行处理能提升运算效率。
  • 线程和进程的关系?

    • 进程中的任意一个线程出错,都会导致一整个进程的崩溃。
    • 线程之间可以共享进程中的数据。可以对进程中的公共数据进行读写操作。
    • 当一个进程关闭之后,操作系统会回收进程所占用的内存。当操作不当导致内存泄漏时,进程关闭后,这些内存也可以被正确回收。
    • 进程之间的内容相互隔离。进程之间如果要进行数据的通信,则需要进程通信机制。
  1. 单进程浏览器时代

image.png

  • 不稳定。第三方插件的崩溃就会导致浏览器的崩溃,渲染引擎的崩溃也会导致整个浏览器崩溃。
  • 不流畅。一个模块卡死,其他模块都无法运行。会导致卡顿。
  • 不安全。通过插件可以获取到操作系统的任意资源,会引发安全问题。
  1. 多进程浏览器时代

image.png

  • 浏览器进程
  • 渲染进程。Chrom会为每一个tab创建一个渲染进程。如果页面a, b属于同一个站点,从a页面点击前往页面b,那么a,b共享一个渲染进程。如果有页面有iframe,iframe也会运行在单独的进程中。
  • GPU进程。早期是为了实现3D CSS效果,随后,Chrome的也看都采用GPU绘制。
  • 网络进程
  • 插件进程

1.2 | TCP协议:如何保证页面文件能被完整送达浏览器?

  1. IP

image.png

  1. UDP 数据包协议 IP 通过 IP 地址信息把数据包发送给指定的电脑,而 UDP 通过端口号把数据包分发给正确的程序。

image.png

  • 对于错误的数据包,UDP不提供重发机制,只是丢弃当前的包。

  • UDP在发送后也无法知道是否能达到目的地。

  • UDP虽然不保证传输数据的可靠性,但是传输速度却非常快。

  • UDP可以运用在一些关注速度,但不严格要求数据完整性的领域。如:在线视频、互动游戏。

  • 使用UDP传输会存在的问题:

    • 数据包在传输过程中容易丢失。
    • 大文件会被拆分成很多小的数据包在不同的路由里传输,并在不用的时间达到接收端,UDP不知道如何组装这些数据包还原成完整的文件。
  1. TCP 传输控制协议

TCP传输控制协议是一种面向连接的、可靠的、基于字节流的传输层通信协议。

TCP协议有以下两个特点:

  • 对于丢失的数据包,会提供重传机制。
  • TCP引入了数据包排序机制,用来保证把乱序的数据包组合成完整的文件。

image.png

TCP的连接过程:

image.png

  • 三次握手。确保双方的接收和发送能力都是正常的。
  • 传输数据。在该阶段,当接收方收到发送方的数据包时,会进行确认操作。即接收端发送确认数据包给发送端,如果在规定时间内,接收端没有收到这个确认包,则说明发生了数据丢失,需要重传。
  • 数据传输完毕之后,四次挥手来保证双方都能断开链接。
  1. 浏览器可以同时打开多个页签,他们端口一样吗?如果一样,数据怎么知道去哪个页签?

    浏览器同时打开多个标签页,端口是一样的,网络进程知道每个tcp链接对应的标签页,所以接收到数据后,会把数据分发给相应的渲染进程。

  2. TCP传送数据时 浏览器端就做渲染处理了么?如果前面数据包丢了 后面数据包先来是要等么?类似的那种实时渲染怎么处理?针对数据包的顺序性?

    当接受到http响应头中的content-type字段时,就开始准备渲染进程的。响应体数据一旦接受到便开始做DOM解析了。数据包丢失,会发生重传机制,丢失和重传,是在tcp的时候就已经解决了,从tcp到http的数据已经是完整的数据了,即便是实时渲染,也是在丢包重传后才能开始渲染。

  3. http和websocket都是属于应用层的协议吗?

    都是应用层协议,而且websocket名字取的比较有迷惑性,其实和socket完全不一样,可以把websocket看出是http的改造版本,增加了服务器向客户端主动发送消息的能力。

  4. 数据在传输的过程中为什么会丢失或者出错?

    比如网络波动,物理线路故障,设备故障,恶意程序拦截,网络阻塞等等

1.3 | HTTP请求流程:为什么很多站点第二次打开速度会很快?

  1. 浏览器端发起HTTP请求流程
  • 构建请求。
  • 查找缓存。
  • 准备IP地址和端口。DNS:把域名映射为IP地址。
  • 等待TCP对列。同一个域名,同时最多只能建立6个TCP连接。
  • 建立TCP连接。
  • 发送HTTP请求。
    • 浏览器向服务器发送请求行,包括了请求方法、请求URI和HTTP版本协议。

image.png

  • 服务器端处理HTTP请求流程
    • 返回请求
    • 断开连接
    • 重定向
  • 服务器响应请求。

image.png

  • 断开连接。 通常情况下,一旦想客户端返回了请求数据,就要关闭TCP连接,但是如果浏览器或者服务器在其头信息中加入Connection:Keep-Alive ,TCP连接将在发送后仍然保持打开状态,保持 TCP 连接可以省去下次请求时需要建立连接的时间,提升资源加载速度。
  • 重定向。

image.png 2. 为什么很多站点第二次打开速度会很快?

主要原因是第一次加载页面过程中,缓存了一些耗时的数据。DNS缓存和页面资源缓存这两块数据是会被浏览器缓存的。其中,DNS 缓存比较简单,它主要就是在浏览器本地把对应的 IP 和域名关联起来。

image.png

第一次请求可以看出,当服务器返回 HTTP 响应头给浏览器时,浏览器是通过响应头中的 Cache-Control 字段来设置是否缓存该资源。
如果缓存过期了,浏览器会继续发起网络请求,并且在HTTP请求头中带上:If-None-Match:"4f80f-13c-3a1xb12a"
服务器收到请求头后,会根据 If-None-Match 的值来判断请求的资源是否有更新。

  • 如果没有更新,则返回304状态码,说明缓存可以继续使用。
  • 如果资源有更新,服务器就直接返回最新资源给浏览器。
  1. 登陆状态是如何保持的? 主要是通过Cookie来实现登陆状态管理的。

image.png 4. http请求所经历的各个阶段

image.png

1.4 | 导航流程:从输入URL到页面展示,这中间发生了什么

image.png

  1. 如果浏览器输入的是查询关键字,地址栏会判断输入的是搜索内容,还是请求的URL。
    • 如果是搜索内容,则会使用浏览器默认的搜索引擎,来合成新的带搜索关键字的URL。
    • 如果判断输入内容符合URL,那么地址栏会根据规则,把这段内容加上协议,合成完整的URL。
    • 在流程继续之前,浏览器还会给当前页面一次beforeunload事件的机会。
  2. 浏览器会通过进程通信,把URL发送给网络进程。
  3. 网络进程拿到请求的URL后,
    • 首先会查到缓存里是否有该资源,如果有,且缓存没有过期,则直接将缓存的资源返回给浏览器进程,不会向服务端发送请求(强缓存)。
    • 如果没有缓存的资源,或者缓存的资源已经过期了,则会向服务器发送请求(协商缓存)。
    • 第一次发送请求,会进行DNS解析,以获取到域名服务器的IP地址,如果请求协议是HTPPS,则还需要建立TLS连接。
    • 利用IP地址和服务器建立TCP连接(三次握手),连接建立后,浏览器端会构建请求行、请求头信息,并把和该域名相关的Cookie等数据附加到请求头中,然后想服务器发送请求。
    • 服务器收到请求后,返回响应数据。
      • 如果响应头的状态码是301/302,那么说明服务器需要浏览器重定向到其他URL,这时网络进程根据响应头的Location字段信息重定向,然后再次发起新的请求。
      • 如果响应信息成功返回,根据响应体的数据类型Content-Type字段,来进行不同的处理。
      • Content-type:text/html时,浏览器会准备渲染进程。
  4. 浏览器将接收到的数据提交给渲染进程。默认情况下,Chrome 会为每个页面分配一个渲染进程,也就是说,每打开一个新页面就会配套创建一个新的渲染进程。但是,当多页页面属于同一个站点时,浏览器会让多个页面直接运行在同一个渲染进程中。
    • 当浏览器进程接收到网络进程的响应头数据之后,便向渲染进程发起“提交文档”的消息;
    • 渲染进程接收到“提交文档”的消息后,会和网络进程建立传输数据的“管道”;
    • 等文档数据传输完成之后,渲染进程会返回“确认提交”的消息给浏览器进程;
    • 浏览器进程在收到“确认提交”的消息后,会更新浏览器界面状态,包括了安全状态、地址栏的 URL、前进后退的历史状态,并更新 Web 页面。

image.png 5. 当文档被提交后,渲染进程便开始页面解析和子资源加载。

1.5 | 渲染流程(上):HTML、CSS和JavaScript,是如何变成页面的?

  1. 构建DOM树 浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。
    构建 DOM 树的输入内容是一个非常简单的 HTML 文件,然后经由 HTML 解析器解析,最终输出树状结构的 DOM。

  2. 样式计算

  • 把CSS转换为浏览器能够理解的结构。 当渲染引擎接收到 CSS 文本时,会执行一个转换操作,将 CSS 文本转换为浏览器可以理解的结构——styleSheets。
    CSS 样式来源主要有三种:
    • 通过 link 引用的外部 CSS 文件。
    • <style>标记内的 CSS。
    • 元素的 style 属性内嵌的 CSS。
  • 转换样式表中的属性值,使其标准化。

image.png

  • 计算出DOM树中每个节点的具体样式。

    • CSS 继承就是每个 DOM 节点都包含有父节点的样式。
    • 层叠是 CSS 的一个基本特征,它是一个定义了如何合并来自多个源的属性值的算法。
  1. 布局阶段 计算出DOM树中可见元素的几何位置。
  • 创建布局树。在显示之前,需要额外地构建一颗只包含可见元素布局树。

image.png

  • 布局计算

问题:

1、如果下载CSS文件失败了,会阻塞DOM树的合成嘛?

2、JS文件会阻塞DOM树的渲染嘛?

基于问题,再思考到了一点:DOMContentLoaded与load的区别、触发时机?

  • DOMContentLoaded :当初始的 HTML 文档被完全加载和解析完成之后,DOMContentLoaded 事件被触发,而无需等待样式表、图像和子框架的完成加载。
  • load :当一个资源及其依赖资源已完成加载时,将触发 load 事件。

image.png 从图中可以看出,DOMContentLoaded触发时间为769ms,load时间触发为1.37s。

  • 在没有css和js的情况下,html文档解析的过程为:

image.png

  • 在有css文件,没有js的情况下,html文档解析的过程为:

image.png

  • 当有js时,html文档解析的过程为:

image.png

所以:

  • css加载不会阻塞DOM树的解析
  • css加载会阻塞DOM树的渲染
  • css加载会阻塞后面js的执行

1.6 | 渲染流程(下):HTML、CSS和JavaScript,是如何变成页面的?

  1. 分层 因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树(LayerTree)
  • 并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。

  • 通常满足下面两点中任意一点的元素就可以被提升为单独的一个图层。

    • 拥有层叠上下文属性的元素会被提升为单独的一层。层叠上下文

    • 需要剪裁(clip)的地方也会被创建为图层。出现裁剪情况的时候,渲染引擎会为文字部分单独创建一个层,如果出现滚动条,滚动条也会被提升为单独的层。

  1. 图层绘制

渲染引擎实现图层的绘制会把一个图层的绘制拆分成很多小的绘制指令,然后再把这些指令按照顺序组成一个待绘制列表。

  1. 栅格化(raster)操作 绘制列表只是用来记录绘制顺序和绘制指令的列表,而实际上绘制操作是由渲染引擎中的合成线程来完成的。
  • 当图层的绘制列表准备好之后,主线程会把该绘制列表提交(commit)给合成线程。
  • 合成线程会将图层划分为图块(tile)

image.png

  • 然后合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。 图块是栅格化执行的最小单位。渲染进程维护了一个栅格化的线程池,所有的图块栅格化都是在线程池内执行的。
  • 栅格化过程都会使用 GPU 来加速生成,使用 GPU 生成位图的过程叫快速栅格化,或者 GPU 栅格化,生成的位图被保存在 GPU 内存中。

image.png

  1. 合成和显示 一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。 浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。

image.png

总结一下完整的渲染流程就是:
1. 渲染进程将 HTML 内容转换为能够读懂的 DOM 树结构。(DOM解析)
2. 渲染引擎将 CSS 样式表转化为浏览器可以理解的 styleSheets,计算出 DOM 节点的样式。(CSSOM树构建)
3. 创建布局树,并计算元素的布局信息。
4. 对布局树进行分层,并生成分层树
5. 为每个图层生成绘制列表,并提交到合成线程。
6. 合成线程将图层分成图块,并在光栅化线程池中将图块转换为位图
7. 合成线程发送绘制图块命令 DrawQuad 给浏览器进程。
8. 浏览器进程根据 DrawQuad 消息生成页面,并显示到显示器上。

重排
更改了元素的几何属性,就会触发重新布局,就会发生重排。重排需要更新完整的渲染流水线,开销也是最大的。

image.png

重绘
更新元素的绘制属性,布局阶段将不会被执行,直接进入绘制阶段。
image.png 合成
如果更改一个既不要布局也不要绘制的属性,渲染引擎将跳过布局和绘制,只执行后续的合成操作,我们把这个过程叫做合成。比如使用transform来实现动画。

image.png

问题: 为什么减少重绘、重排能优化 Web 性能吗?那又有那些具体的实践方法能减少重绘、重排呢?