技术知识文章集合TECHNICAL ARCHIVE · 457 DOCUMENTS

显示模式

登录
ARCHIVE DOCUMENTBR

浏览器工作原理:从导航、获取资源到解析与渲染

所属馆藏
Browser
文件格式
Markdown
原始路径
Browser/29-浏览器工作原理_2
本文目录9 个章节
  1. 一、导航:用户请求一个页面
  2. 二、获取数据:HTTP 请求和响应
  3. 三、HTML 解析:字节流到 DOM
  4. 四、解析 CSS:CSSOM 与级联
  5. 五、JavaScript 引擎执行代码
  6. 六、可访问性树
  7. 七、从 DOM 和样式到像素
  8. 八、用开发者工具验证,而不是背固定军规
  9. 参考资料

浏览器工作原理:从导航、获取资源到解析与渲染

Category(分类): Browser Status: 已更新

浏览器工作原理可以用一句话概括:用户发起导航后,浏览器解析地址、建立或复用网络连接,获取 HTML 及其依赖资源,再把文本解析成对象模型,经过样式计算、布局、绘制、栅格化和合成,最终把像素交给屏幕显示。

这个模型适合学习和定位问题,但不是所有页面都严格依次执行所有步骤。缓存、Service Worker、预连接、HTTP/2 多路复用、HTTP/3、BFCache、已有渲染进程以及增量更新,都可能改变实际路径。

一、导航:用户请求一个页面

导航可能由以下行为触发:

  • 在地址栏输入 URL;
  • 点击链接、提交表单或调用 location
  • 前进/后退、刷新、打开新窗口;
  • Service Worker、浏览器扩展或应用代码参与的导航。

在真正访问网络前,浏览器还可能命中 HTTP 缓存、Service Worker、BFCache,或者复用已有连接。命中 BFCache 时,页面甚至可以从历史快照恢复,不必重新下载和解析全部资源。

1. 解析 URL 和查找地址

https://example.com/articles?id=42#intro 为例:

部分示例作用
schemehttps指定访问协议
authorityexample.com主机名,可能还包含端口和用户信息
path/articles资源路径
query?id=42传给服务器的查询参数
fragment#intro页面内片段,通常不会发送给服务器

浏览器会先判断输入内容是 URL 还是搜索关键词,并规范化 URL。片段标识符通常只在浏览器端用于定位文档中的元素,不会出现在 HTTP 请求目标中。

2. DNS 查询

主机名需要解析为一个或多个 IP 地址,但“第一次访问才会 DNS 查询”是过时的简化说法。浏览器、操作系统、路由器、递归 DNS 解析器和权威 DNS 都可能缓存结果;缓存过期、网络切换、连接迁移或记录变化时仍然可能重新查询。

DNS 查询和缓存的示意

典型链路可以概括为:

  1. 浏览器检查自身缓存和已有连接;
  2. 操作系统检查本地缓存,必要时向配置的递归解析器请求;
  3. 递归解析器根据 NS、A/AAAA、CNAME 等记录向权威服务器查询;
  4. 返回 IPv4 和/或 IPv6 地址,并根据 TTL 缓存;
  5. 浏览器根据地址、端口、代理和网络策略选择连接。

域名解析结果缓存示意

DNS 根服务器不是“600 多台固定服务器”。通常所说的根服务器是 13 个根服务标识,背后通过 Anycast 在全球部署了大量实例。开发者通常不需要直接访问根服务器,应用也不应假设某个域名只有一个固定 IP。

DNS 查询还可能通过 DoH 或 DoT 发送给解析服务。它们可以减少本地网络对 DNS 明文的观察,但不能替代 HTTPS,也不能隐藏后续连接的全部元数据。

3. 建立或复用连接

如果已有适合的连接,浏览器会尽量复用,而不是每个资源都重新握手。连接是否能复用取决于协议版本、主机、端口、代理、证书、连接状态和浏览器调度策略。

HTTP/1.1 和 HTTP/2:TCP

在 HTTP/1.1 或 HTTP/2 over TCP 的场景下,通常先进行 TCP 三次握手:

  1. 客户端发送 SYN,声明初始序列号和能力;
  2. 服务端回复 SYN-ACK
  3. 客户端回复 ACK,连接进入可传输状态。

TCP 三次握手示意

TCP 提供可靠的有序字节流,但它不理解 HTTP,也不负责加密。数据包丢失时,TCP 会通过确认、重传、拥塞控制和流量控制等机制处理。连接关闭通常还会涉及 FIN/ACK 交互,不能简单理解为固定的“发送四个包就结束”。

“同一域名最多 6 个 TCP 连接”是旧浏览器和 HTTP/1.1 场景中的经验值,不能作为今天的通用规则。HTTP/2 可以在一个连接中多路复用多个请求,浏览器还会根据资源优先级和服务器能力调整连接数量。

HTTP/3:QUIC

HTTP/3 使用 QUIC,QUIC 基于 UDP,但自己提供可靠传输、流、多路复用、拥塞控制和 TLS 1.3 集成。因此 HTTP/3 不需要先建立 TCP 连接;网络路径改变时,QUIC 还可以利用连接 ID 尝试维持连接。是否使用 HTTP/3 由客户端和服务端通过 Alt-Svc、HTTPS 记录等机制协商,失败时可以回退到其他版本。

4. TLS 协商

HTTPS 不是一个替代 HTTP 的应用层协议,而是把 HTTP 放在 TLS 保护的连接中。TLS 提供机密性、完整性和对端身份认证,但不能让服务器“看不见”请求的所有元数据。

TLS 握手和证书交换示意

现代 TLS 1.3 的学习模型如下:

  1. 客户端发送支持的版本、密码套件、随机数和临时密钥交换参数(常见为 ECDHE key share);
  2. 服务端选择参数,发送自己的 key share、证书链和握手签名;
  3. 浏览器验证证书链、域名的 SAN、有效期、用途和签名,并确认根证书来自受信任的信任库;
  4. 双方通过临时密钥交换得到共享秘密,再用 HKDF 派生握手密钥和应用数据密钥;
  5. 握手消息使用认证加密保护,双方发送 Finished 后开始传输应用数据。

不要把旧式 RSA 密钥交换当成现代 HTTPS 的统一流程,也不要说“服务器用私钥加密数据、浏览器用公钥解密”。数字签名用于证明握手消息确实由证书对应的私钥方签名;实际 HTTP 数据通常使用派生出的对称 AEAD 密钥加密。TLS 1.2 仍可能存在于兼容场景,但新系统应优先使用 TLS 1.3,并关闭已知不安全的旧协议和密码套件。

二、获取数据:HTTP 请求和响应

1. HTTP 请求

完成必要的连接准备后,浏览器请求 HTML。请求由请求方法、目标、协议版本、头字段和可选请求体组成:

GET /articles?id=42 HTTP/2
Host: example.com
Accept: text/html,application/xhtml+xml
Accept-Encoding: gzip, br
Accept-Language: zh-CN,zh;q=0.9
User-Agent: <browser>

HTTP 方法不只有 GET 和 POST,还包括 PUTPATCHDELETEHEADOPTIONS 等。GET 通常用于获取资源,POST 常用于提交数据,但是否携带请求体由方法语义和具体实现决定,不能把“请求体只有 POST 才存在”当成协议规则。

HTTP 请求组成示意

请求头可能包含缓存验证信息、Cookie、认证信息、来源、内容协商和追踪防护字段。打开开发者工具的 Network 面板,可以查看真实的请求方法、URL、请求头、响应头、Timing 和优先级。

2. HTTP 响应

响应包括状态码、头字段和可选的响应体:

HTTP/2 200
Content-Type: text/html; charset=utf-8
Cache-Control: no-cache
Content-Encoding: br

<!doctype html>

状态码并不是只有 200 才表示成功:

  • 2xx 表示请求已成功处理;
  • 3xx 表示重定向或缓存复用,例如 304 Not Modified
  • 4xx 表示请求或权限方面的问题;
  • 5xx 表示服务端处理失败。

HTTP 请求头示意

一个页面的 HTML 可能引用其他资源:

<!doctype html>
<html lang="zh-CN">
  <head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1">
    <title>我的页面</title>
    <link rel="stylesheet" href="styles.css">
    <script src="main.js" defer></script>
  </head>
  <body>
    <h1>这是我的页面</h1>
    <p><a href="/about">关于我们</a></p>
    <img src="my-image.jpg" alt="示例图片">
  </body>
</html>

浏览器收到 HTML 后,会继续发现并请求 CSS、脚本、图片、字体、模块和 iframe 等依赖资源;它们是否立即请求、是否阻塞渲染以及优先级如何,取决于元素类型、属性、缓存和调度器。

HTTP 响应示意

3. TTFB、拥塞控制和连接复用

TTFB(Time to First Byte)通常表示从一次请求的开始到收到响应第一个字节的时间。它可以拆成排队、DNS、连接、TLS、服务端处理和响应传输等部分。对于导航监控,浏览器提供 PerformanceNavigationTiming,不要把“第一个 HTML 数据包通常是 14KB”作为固定事实。

TCP 慢启动会根据拥塞窗口、往返时延、确认和丢包等情况逐渐调整发送速率。初始窗口、分段大小和实际首包大小会随协议、系统、网络和配置变化;客户端在收到数据后会发送 ACK,丢包也不等于“客户端停止发送 ACK”。HTTP/2、HTTP/3 还会在更高层进行流调度和多路复用。

三、HTML 解析:字节流到 DOM

浏览器通常边接收 HTML 边解析,而不是等整个文件下载完成后才开始工作。HTML 解析包含两个相互配合的阶段:标记化(tokenization)和建树(tree construction)。

1. 标记化和建树

WHATWG HTML 标准定义了 HTML tokenizer、插入模式、开放元素栈、活动格式化元素列表等规则。HTML 解析器是带状态的容错算法,不应简单当作普通 XML 解析器,也不能只用“正则表达式匹配标签”替代。

HTML 标记化示意

例如,浏览器会对缺少闭合标签、错误嵌套、表格结构和重复 form 等情况执行规范规定的纠错。最终 DOM 可能与原始字符串看起来不完全相同,因此调试时应查看 Elements 面板中的 DOM,而不是只看 View Source。

<!doctype html>
<html>
  <head>
    <title>HTML parsing</title>
  </head>
  <body>
    <p>Hello <strong>browser</strong></p>
  </body>
</html>

DOM 树示意

DOM 是文档的对象模型,包含元素、文本、注释和属性等节点。DOM 节点越多不必然意味着页面一定慢,但复杂的选择器、布局关系、样式变化和频繁更新会增加后续工作量。

2. 解析器、阻塞资源和预加载扫描器

经典的同步脚本可能暂停 HTML 解析:

<script src="app.js"></script>

脚本需要执行时,浏览器可能等待脚本下载;脚本还可能依赖已经发现的样式。更常见的现代写法是:

<script src="app.js" defer></script>
<script type="module" src="main.js"></script>
<script async src="analytics.js"></script>
  • defer 脚本在文档解析完成后、DOMContentLoaded 前按文档顺序执行;
  • async 脚本下载完成后尽快执行,多个脚本之间没有执行顺序保证;
  • 模块脚本默认延迟执行,并支持模块依赖图;
  • asyncdefer 和模块脚本的行为还会受到脚本是否为经典脚本、是否动态插入等因素影响;
  • document.write()、同步脚本和脚本执行期间的 DOM 操作可能改变解析流程。

样式表通常会阻塞首次渲染,但不等同于“HTML 解析器永远停在 CSS 上”。经典脚本可能等待已发现的样式表,字体一般不会阻塞 HTML tokenizer。preload、预连接和预加载扫描器可以提前发现资源,但它们不等同于完整的第二个 HTML 解析器。

从字节流到 DOM 的流程

四、解析 CSS:CSSOM 与级联

浏览器会把样式表解析成可供样式计算使用的内部结构。document.styleSheets 提供 CSSOM 的一部分访问能力,但 CSSOM 不是一个与 DOM 完全对称、所有内部实现都公开的“规则树”。

CSS 解析和 CSSOM 示意

样式计算会综合:

  • 用户代理样式、作者样式和用户样式;
  • 选择器匹配结果;
  • 继承、层叠顺序、来源和 !important
  • 媒体查询、容器查询、层叠层和自定义属性;
  • 字体、视口、环境变量和动画状态。

CSS 选择器通常从右侧候选部分开始匹配是实现上的常见优化,但“CSS 规则从右到左阅读”不是 CSS 语言的语义,也不能据此武断判断所有选择器性能。

body {
  color: #333;
  font-size: 16px;
}

article {
  color: tomato;
}

article .title {
  margin-inline-start: 1rem;
}

article p {
  color: #555;
}
<p><a href="/docs">文档链接</a></p>
a {
  color: red;
}

p a {
  color: blue;
}

第二条规则的选择器更具体,因此在没有其他来源和层叠条件干预时,链接会显示为蓝色。实际判断应使用现代 specificity 规则,而不是只比较选择器字符串长度。

CSSOM 计算样式示意

五、JavaScript 引擎执行代码

浏览器渲染引擎负责 HTML、CSS、布局和绘制,JavaScript 引擎则负责 ECMAScript 代码的解析和执行。两者通过 DOM、Web IDL、事件循环等接口协作,但不是同一个“引擎”。

常见 JavaScript 引擎包括:

  • V8:用于 Chromium 系浏览器,也用于 Node.js、Deno 等运行时;
  • JavaScriptCore:WebKit 使用的 JavaScript 引擎;
  • SpiderMonkey:Firefox 使用的 JavaScript 和 WebAssembly 引擎;
  • Chakra:旧版 Microsoft Edge 使用过的引擎,现代 Edge 已迁移到 Chromium/V8。

现代引擎并不是简单的“逐行解释器”或“下载后立刻编译成机器码”。一个简化模型是:源码经过词法分析和语法分析生成 AST,之后可能生成字节码,由解释器执行;运行中收集类型和热点信息,再由基线编译器或优化编译器生成更高效的机器码。优化假设不成立时还可能反优化。

const age = 25
const message = `age: ${age}`
console.log(message)

JIT 是引擎实现策略,不是 ECMAScript 语法要求,也不能把“JavaScript 是解释型语言”或“JavaScript 是编译型语言”当成完整结论。WebAssembly 也不是“WebAssembley”,它是另一种具有明确格式和执行模型的 Web 代码形式。

六、可访问性树

除了 DOM、样式和布局相关结构,浏览器还会为辅助技术提供可访问性树或等价的可访问性表示。它通常包含角色(role)、可访问名称(name)、状态、属性、值和父子关系。

可访问性树示意

屏幕阅读器并不是直接读取 DOM 字符串,而是通过操作系统的辅助技术接口获取浏览器暴露的语义信息。可访问性树的生成和更新由浏览器实现决定,不应假设每次 DOM 更新都会同步、完整地重建一棵公开的树。

优先使用语义 HTML:

<button type="button" aria-expanded="false" aria-controls="menu">
  打开菜单
</button>
<nav id="menu" hidden>
  <a href="/docs">文档</a>
</nav>

只有在原生元素无法表达语义时再使用 ARIA。ARIA 可以补充角色和状态,但不能修复键盘行为、焦点管理、可见文本和实际交互缺失的问题。

开发者工具中的无障碍信息

七、从 DOM 和样式到像素

早期教程常用“DOM + CSSOM = Render Tree”描述渲染树。这个模型仍然有助于理解哪些节点参与显示,但现代浏览器内部通常还会维护布局树/fragment tree、属性树、绘制列表、合成层和图块等结构,不同引擎的名称和边界并不相同。

1. 样式计算和布局

布局阶段计算参与布局的盒子的尺寸和位置。display: none 的节点通常不产生布局盒;visibility: hidden 通常仍占据空间;伪元素、匿名盒、滚动容器和 iframe 可能产生额外的布局对象。

布局树和几何计算示意

布局可能是全量,也可能只更新受影响的局部区域。窗口变化、字体加载、内容变化和几何属性变化都可能扩大影响范围,但不能从一个 CSS 属性名称准确推断实际成本。

2. 绘制、栅格化和合成

绘制阶段把背景、边框、文本、阴影和图片等转换为绘制指令或显示列表;栅格化再把需要显示的绘制内容转换为图块和位图;最后合成器根据层、变换、裁剪和透明度把结果合成到目标表面。

绘制阶段示意

合成层和图块示意

transformopacity 在满足浏览器合成条件时可能只需要更新合成属性,从而跳过布局或重新绘制。但这不是所有 transform 都必然“只走 GPU”,filter、阴影、内容变化、内存压力、设备能力和浏览器启发式都可能让流程不同。

图层组织示意

八、用开发者工具验证,而不是背固定军规

  • Network 面板:查看 DNS、连接、TLS、请求优先级、缓存和 TTFB;
  • Performance 面板:查看长任务、脚本、Recalculate Style、Layout、Paint、Raster 和 Composite;
  • Elements 的 Computed/Accessibility 面板:查看计算样式、布局盒和可访问性信息;
  • Rendering 面板:查看帧渲染统计、布局偏移、绘制边界等辅助信息;
  • Lighthouse、CrUX 和 RUM:从实验室与真实用户两侧评估体验。

遇到性能问题时,应先用录制结果确认瓶颈,再决定是否改变 DOM 结构、样式、脚本、资源优先级或渲染策略。不要把“固定 6 个连接”“一定有 Render Tree”“所有动画都使用 GPU”当成跨浏览器、跨版本的规则。

参考资料

457 DOCUMENTS · 10 COLLECTIONS
ARCHIVE SEARCH457 篇文章

SEARCH GUIDE

输入关键词开始搜索

支持搜索文章标题、所属分类和原始文档路径。

按分类浏览

10 COLLECTIONS