介绍
对我们开发者来说,我们需要使页面内容能够快速加载且流畅交互,因此理解浏览器的工作原理有助于开发者懂得如何去提升性能。
导致web性能问题的原因主要有两种
- 网络延迟
- 大部分情况下的浏览器单线程执行
- 浏览器在执行一个任务之前会从头到尾完成一个任务,然后才会接受另一个任务。为了实现流畅的交互,渲染时间非常关键,我们需要确保主线程能够完成交给它的所有工作,并且始终能够处理用户交互。
渲染流程
Step 1 导航
导航是加载 web 页面的第一步。它发生在以下情形:用户通过在地址栏输入一个 URL、点击一个链接、提交表单或者是其他的行为。 Web 性能优化的目标之一就是缩短导航完成所花费的时间
1. 1 DNS查询
导航的第一步是要去寻找页面资源的位置, 如果导航到 https://example.com,HTML 页面被定位到 IP 地址为 93.184.216.34 的服务器, 如果以前没有访问过这个网站,就需要进行 DNS 查询。
通过DNS查询最终会获得一个IP地址,请求一次之后,这个IP地址会被缓存一段时间,这样后续可以从缓存里面检索IP地址而不需要通过查询服务器去查询IP地址。
1.2 TCP握手
一旦获取到服务器的 IP 地址,浏览器就会通过 TCP 三次握手与服务器建立连接。三次握手依次为:
SYN → SYN-ACK → ACK
- **第一次握手(SYN)**客户端向服务器发送 SYN 报文,服务器成功接收。
- **第二次握手(SYN-ACK)**服务器回复 SYN-ACK 报文:其中 ACK 表示已收到客户端的 SYN,SYN 表示服务器已准备好建立连接,客户端成功接收。
- **第三次握手(ACK)**客户端发送 ACK 报文,表示已收到服务器的 SYN,服务器成功接收。
至此,TCP 连接正式建立。
1.3 TLS协商
若当前使用的是 HTTPS 协议,在 TCP 三次握手建立可靠连接后,还会额外进行一次 TLS 握手 。这次握手的核心作用是:协商加密算法、交换会话密钥、验证服务器身份,从而为后续传输的数据提供加密保护,确保通信安全。 这个TLS协商,需要在实际发送内容请求之前,再往返服务器五次。

Step 2 响应
一旦我们建立了和 web 服务器的连接,浏览器就会代表用户发送一个初始的 HTTP GET 请求。
当浏览器向服务器发送 HTTP GET 请求后,服务器会返回一个 HTTP 响应。
这个响应包含:
- 状态行(Status Line)
- 响应头(Headers)
- 响应体(Body)
响应体通常是一个 HTML 文档,例如:
<!doctype html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8" />
<title>简单的页面</title>
<link rel="stylesheet" href="styles.css" />
<script src="myscript.js"></script>
</head>
<body>
<h1 class="heading">我的页面</h1>
<p>含有<a href="<https://example.com/about>">链接</a>的段落。</p>
<div>
<img src="myimage.jpg" alt="图像描述" />
</div>
<script src="anotherscript.js"></script>
</body>
</html>
首字节时间(TTFB)
当我们谈到"响应"时,一个非常重要的性能指标是:
TTFB(Time To First Byte)------ 首字节时间
它指的是:
从用户发起请求,到浏览器收到响应的第一个字节之间的时间。
TTFB 包含:
- DNS 查询
- TCP 建立连接
- TLS 握手(如果是 HTTPS)
- 服务器处理请求
- 服务器开始发送数据
TTFB 越短,页面响应越快。
需要注意,就是HTTP 响应通常是以流式方式传输的,浏览器并不会等待整个 HTML 下载完成后才开始解析,而是边接收数据边进行解析。
在传输层,TCP 会通过"慢启动"和拥塞控制机制逐步增加发送数据的数量:一开始只发送少量数据(通常约 14KB,取决于初始拥塞窗口大小),在收到客户端的确认(ACK)后再逐步扩大传输规模,以在网络利用率和拥塞风险之间取得平衡。因此,如果首个 HTML 文档体积较小,往往可以在一个往返时间内完成传输,从而更早进入解析阶段,提高页面首屏加载性能。
Step3 解析
"解析"是指浏览器将通过网络接收到的数据转换为内部可操作结构的过程,主要包括:
- 构建 DOM
- 构建 CSSOM
最终这些结构会被渲染器用于在屏幕上绘制页面。
3.1 构建DOM树
首先,浏览器会解析 HTML 文档,将标记(Markup)转换为 DOM 树。
<html>元素是文档的根节点- DOM 树描述了文档的结构和层级关系
- 被嵌套的标签会成为父节点的子节点
DOM 树本质上是一棵树结构,用来表示页面内容。
DOM 节点数量越多,构建 DOM 所需时间就越长,因此过于复杂的 DOM 结构会影响性能。
3.2 构建CSSOM树
在构建 DOM 的同时或之后,浏览器会解析 CSS 并生成 CSSOM 树。
- CSSOM 是 CSS 的对象模型
- 它包含开发者编写的样式规则
- 也包含浏览器默认的用户代理样式(User Agent Stylesheet)
DOM 和 CSSOM 是两个独立的数据结构,但最终会结合在一起参与后续渲染。
Step 4 渲染
渲染阶段主要包括:
- 样式计算(Style) 构建渲染树
- 布局(Layout) 计算节点尺寸位置
- 绘制(Paint)
- 合成(Composite)
在解析阶段生成的 DOM 和 CSSOM 会合并生成渲染树(Render Tree),然后基于该树完成后续流程。
4.1 样式
先是将DOM树与CSSOM树组合成渲染树,计算样式树或渲染树的构建从 DOM 树的根开始,遍历每个可见节点。
渲染树标识了哪些节点会显示(即使不可见)及其计算样式。
4.2 布局
布局阶段会计算每个渲染节点的几何信息,包括:
- 位置
- 尺寸
- 盒模型信息
这一过程也被称为 回流(Reflow)。
当页面的尺寸或结构发生变化时(例如窗口大小变化、元素尺寸改变),就会触发重新布局。
布局是一个昂贵操作,频繁触发会严重影响性能。
4.3 绘制
最后是将各个节点绘制到屏幕上,其中第一次的绘制被称为首次有意义的绘制。在绘制或光栅化阶段,浏览器将在布局阶段计算的每个盒子转换为屏幕上的实际像素。绘制涉及将元素的每个可见部分绘制到屏幕上,包括文本、颜色、边框、阴影以及按钮和图像等替换元素。
绘制可以将布局树中的元素分解为多个层。将内容提升到 GPU 上的层(而不是 CPU 上的主线程)可以提高绘制和重新绘制性能。有一些特定的属性和元素可以实例化一个层,包括 <video> 和 <canvas>,任何 CSS 属性为 opacity 、3D transform、will-change 的元素,还有一些其他元素。这些节点将与子节点一起绘制到它们自己的层上,除非子节点由于上述一个(或多个)原因需要自己的层。
分层确实可以提高性能,但在内存管理方面成本较高,因此不应作为 Web 性能优化策略的过度使用。
4.4合成
当文档的各个部分以不同的层绘制,相互重叠时,必须进行合成,以确保它们以正确的顺序绘制到屏幕上,并正确显示内容。
当页面继续加载资源时,可能会发生回流(回想一下我们迟到的示例图像),回流会触发重新绘制和重新合成。
Step 5 交互
当页面完成绘制后,并不意味着页面已经完全"可交互"。
如果此时主线程正在执行 JavaScript(例如在 onload 之后执行大量脚本),主线程可能被阻塞,从而无法响应:
- 滚动
- 点击
- 触摸操作
可交互时间(TTI)
TTI(Time to Interactive)用于衡量从页面开始加载到页面真正可交互所花费的时间。
页面被认为"可交互"需要满足:
- 首次内容绘制已经完成
- 页面在 50ms 内能够响应用户输入
如果主线程正在解析、编译或执行 JavaScript,就无法在 50ms 内响应用户操作,从而影响用户体验。