浏览器输入 URL 发生了什么

前言

前端工程师几乎每天都要和浏览器打交道,所以,了解浏览器是如何工作的,能够使我们快速定位问题和提升用户体验。

用户输入

地址栏会判断是搜索内容还是请求 URL。

  • 如果是搜索内容,地址栏会使用浏览器默认的搜索引擎,来合成新的带搜索关键字的 URL。
  • 如果判断输入内容符合 URL 规则,那么地址栏会根据规则,把这段内容加上协议,合成为完整的 URL。

URL 请求过程

  1. 查找本地缓存是否有资源,如果有就直接获取,没有的话就进入下一步。
  2. 进行 DNS 解析,以获取请求的 IP 地址。如果协议是 https 还需要进行 TLS 连接。
  3. IP 地址和服务器的 TCP 连接。
  4. 建立连接后,发送请求头等信息给服务器。
  5. 服务器接收到请求信息,将响应头等数据返回给客户端。
    • 重定向:网络进程解析响应头,如果状态码 301 或者 302,那么说明重定向到其他 URL,而这个 URL 是 Location 字段值。
    • 响应数据类型处理:Content-Type 是 HTTP 头中一个非常重要的字段, 它告诉浏览器服务器返回的响应体数据是什么类型,然后浏览器会根据 Content-Type 的值来决定如何显示响应体的内容。

准备渲染进程

什么是同一站点

  • 根域名:极客时间(geekbang.org)。
  • 协议:http:// 或 https://。
  • 根域名下的所有子域名和不同的端口。

打开一个新页面的渲染进程策略

  • 通常情况下,打开新的页面都会使用单独的渲染进程。
  • 如果从 A 页面打开 B 页面,且 A 和 B 都属于同一站点的话,那么 B 页面复用 A 页面的渲染进程;如果是其他情况,浏览器进程则会为 B 创建一个新的渲染进程。

提交文档

  1. 网络进程告知浏览器进程,可以让渲染进程过来取资源了。
  2. 浏览器进程通知渲染进程,渲染进程打开与网络进程之间的传输通道,等所有资源都传输完后,渲染进程通知浏览器进程。
  3. 浏览器进程收到渲染进程的提交完成信息后,就开始更新安全状态、地址栏的 URL、前进后退的历史状态,并更新 Web 页面。

渲染阶段

构建 DOM 树

这是因为浏览器无法直接理解和使用 HTML,所以需要将 HTML 转换为浏览器能够理解的结构——DOM 树。

样式计算

  1. 把 CSS 转换为浏览器能够理解的结构——styleSheets。
  2. 转换样式表中的属性值,使其标准化。即浏览器需要将 css 的所有属性值转换为渲染引擎容易理解的、标准化的计算值。
  3. 计算出 DOM 树中每个节点的具体样式,运用继承规则和层叠规则。

总之,样式计算阶段的目的是为了计算出 DOM 节点中每个元素的具体样式,在计算过程中需要遵守 CSS 的继承和层叠两个规则。这个阶段最终输出的内容是每个 DOM 节点的样式,并被保存在 ComputedStyle 的结构内。

布局阶段

计算出 DOM 树中可见元素的几何位置,我们把这个计算过程叫做布局。

  1. 创建布局树:遍历 DOM 树中的所有可见节点,并把这些节点加到布局树中,而不可见的节点会被布局树忽略掉。
  2. 布局计算

分层

因为页面中有很多复杂的效果,如一些复杂的 3D 变换、页面滚动,或者使用 z-indexing 做 z 轴排序等,为了更加方便地实现这些效果,渲染引擎还需要为特定的节点生成专用的图层,并生成一棵对应的图层树。

通常情况下,并不是布局树的每个节点都包含一个图层,如果一个节点没有对应的层,那么这个节点就从属于父节点的图层。

创建新图层的条件:

  1. 拥有层叠上下文属性的元素会被提升为单独的一层:明确定位属性的元素、定义透明属性的元素、使用 CSS 滤镜的元素等,都拥有层叠上下文属性。
  2. 需要剪裁(clip)的地方也会被创建为图层。

图层绘制

绘制一个元素通常需要好几条绘制指令,因为每个元素的背景、前景、边框都需要单独的指令去绘制。所以在图层绘制阶段,输出的内容就是这些待绘制列表。

栅格化操作

我们把用户可以看到的这个部分叫做视口。

有的图层很大,这时候为了减少渲染引擎不必要的开销,合成线程会将图层划分为图块。

维基百科:位图(英语:Bitmap,台湾称为点阵图),又称栅格图(Raster graphics),是使用像素阵列(Pixel-array/Dot-matrix点阵)来表示的图像。

合成线程会按照视口附近的图块来优先生成位图,实际生成位图的操作是由栅格化来执行的。所谓栅格化,是指将图块转换为位图。可以理解为在视口呈现的图像。

合成和显示

一旦所有图块都被光栅化,合成线程就会生成一个绘制图块的命令——“DrawQuad”,然后将该命令提交给浏览器进程。浏览器进程里面有一个叫 viz 的组件,用来接收合成线程发过来的 DrawQuad 命令,然后根据 DrawQuad 命令,将其页面内容绘制到内存中,最后再将内存显示在屏幕上。到这里,经过这一系列的阶段,编写好的 HTML、CSS、JavaScript 等文件,经过浏览器就会显示出漂亮的页面了。

渲染阶段总结一张图如下:

来自课程原图

扩展:渲染阶段

什么是重排

重排是在网络浏览器中执行的一个流程,用于重新计算文档中各元素的位置和几何形状,以便重新呈现该文档的部分内容或全部内容。

来自课程原图

重排需要更新完整的渲染流水线,所以开销也是最大的。

触发重排的操作

  1. 页面首次渲染,这是开销最大的一次重排。
  2. 浏览器窗口尺寸改变。
  3. 元素位置和尺寸发生改变。
  4. 新增和删除可见元素。
  5. 内容发生改变(文字数量或图片大小等等)。
  6. 元素字体大小变化。
  7. 激活 css 伪类(:hover)。
  8. 设置 style 属性。
  9. 查询某些属性或调用某些方法:offsetWidth、offsetHeight 等,除此之外,当我们调用 getComputedStyle 方法,或者 IE 里的 currentStyle 时,也会触发重排,原理都是求一个“即时性”和“准确性”。

常见引起重排属性和方法如下:

width
height
margin
padding
display
border-width
border
position
overflow
font-size
vertical-align
min-height
clientWidth
clientHeight
clientTop
clientLeft
offsetWidth
offsetHeight
offsetTop
offsetLeft
scrollWidth
scrollHeight
scrollTop
scrollLeft

scrollIntoView()
scrollTo()
getComputedStyle()
getBoundingClientRect()
scrollIntoViewIfNeeded()

什么是重绘

当一个元素的外观发生改变,但没有改变布局,重新把元素外观绘制出来的过程,叫做重绘。

来自课程原图

相较于重排操作,重绘省去了布局和分层阶段,所以执行效率会比重排操作要高一些。

重绘不一定导致重排,但重排一定会导致重绘。

触发重绘的操作

常见引起重排属性如下:

color
border-style
visibility
background
text-decoration
background-image
background-position
background-repeat
outline-color
outline
outline-style
border-radius
outline-width
box-shadow
background-size

什么是合成

合成指的是跳过重排和重绘阶段,只执行后续的合成操作。

来自课程原图

这样的效率是最高的,因为是在非主线程上合成,并没有占用主线程的资源,另外也避开了布局和绘制两个子阶段,所以相对于重绘和重排,合成能大大提升绘制效率。

结语

浏览器输入 URL 发生了什么?

  1. 用户输入查询关键字。
    • 如果是搜索内容,那么搜索引擎会合成带有关键字的 URL。
    • 如果是符合规则的 URL,直接进入下一步。
  2. 浏览器进程通过 IPC 通信,把 URL 请求发送至网络进程。
  3. 网络进程接收到 URL 请求后检查本地缓存是否有该请求资源,如果有就返回给浏览器进程,没有就进入下一步。
  4. 网络进程向 Web 服务器发起请求过程如下:
    • 4-1、DNS 解析以获取请求域名的 IP 地址,如果协议是 HTTPS 还需要建立 TLS 连接。
    • 4-2、利用ip地址和服务器建立 TCP 连接。
    • 4-3、构建请求头信息。
    • 4-4、发送请求头信息。
    • 4-5、服务器响应后,网络进程接收响应头和响应信息,并解析响应内容。
  5. 网络进程解析响应流程如下:
    • 5-1、检查状态码,如果是 301/302,则需要重定向,自动从 Location 中读取地址,重新进行第 3 步,如果是 200,则继续处理请求。
    • 5-2、200 响应处理:检查响应类型 Content-Type,如果是字节流类型,则将该请求提交给下载管理器,该导航流程结束,不再进行后续的渲染,如果是 html 则通知浏览器进程准备渲染进程准备进行渲染。
  6. 准备渲染进程:浏览器进程检查当前 url 是否和之前打开渲染进程的根域名相同,如果相同,则复用原来的进程,如果不同,则开启新的渲染进程。
  7. 更新界面状态
    • 7-1、渲染进程准备好后,浏览器向渲染进程发起“提交文档”的消息,渲染进程接收到消息和网络进程建立传输数据的“管道”。
    • 7-2、渲染进程接收完数据后,向浏览器发送“确认提交”。
    • 7-3、浏览器进程接收到确认消息后更新浏览器界面状态:安全、地址栏url、前进后退的历史状态、更新 web 页面。
  8. 渲染阶段
    • 8-1、构建 DOM 树。
    • 8-2、样式计算。
    • 8-3、布局阶段。
    • 8-4、分层。
    • 8-5、生成绘制指令。
    • 8-6、分块。
    • 8-7、光栅化。
    • 8-8、合成显示。

这是学习《浏览器工作原理与实践》在新窗口打开李兵老师课程的笔记。