Skip to main content
我对浏览器渲染的理解分了几次补:起初只记得从 URL 到页面的大致流程,后来才弄清每个阶段各自在解决什么问题,最后能按需要拆到某一步的细节。

Q1: 从输入 URL 到页面展示,经历了哪些步骤?

1

URL 解析与导航开始

用户在地址栏输入内容后,浏览器首先判断是搜索关键词还是 URL。如果包含 . 且没有空格,浏览器会补全协议(默认 https://)并开始导航。浏览器主进程通过 IPC 通知网络进程发起请求。
2

DNS 解析

浏览器先查自身 DNS 缓存,再查操作系统缓存和 hosts 文件,最后由本地 DNS 服务器执行迭代查询——根 DNS 返回 .com 服务器地址,.com DNS 返回权威服务器地址,权威 DNS 返回最终的 A 记录。
3

TCP 三次握手与 TLS 握手

客户端与服务器通过三次握手建立 TCP 连接(SYN → SYN+ACK → ACK)。HTTPS 场景下还需要 TLS 握手——TLS 1.3 优化为 1-RTT,支持 0-RTT 恢复。QUIC(HTTP/3)将传输层握手和 TLS 握手合并,首次连接只需 1-RTT。
4

HTTP 请求与服务器响应

浏览器发送 HTTP 请求报文(请求行 + 请求头 + 请求体),服务器返回响应(状态码 + 响应头 + 响应体)。HTTP/1.1 有队头阻塞,HTTP/2 多路复用解决 HTTP 层阻塞,HTTP/3 用 QUIC 解决 TCP 层阻塞。
5

浏览器解析与渲染

渲染进程将 HTML 解析为 DOM 树,CSS 解析为 CSSOM 树,两者合并为渲染树。然后经过 Layout(几何计算)、Paint(绘制指令)、Composite(GPU 合成)三个阶段,最终输出到屏幕。
浏览器渲染解决的核心问题:
浏览器渲染的本质是把 HTML/CSS 字节流经过解析、布局、绘制、合成,最终变成屏幕上的像素。

没有渲染流程

如果浏览器收到 HTML 后直接尝试绘制像素,就像一个建筑工人拿到一摞建材清单后直接砌墙——没有图纸(DOM 树)、没有结构设计(Layout),最终只能得到一堆乱七八糟的砖块。

引入渲染流程

有了渲染流程后,就像建筑工地有了完整的流程:先读清单建骨架(DOM),再画装修图纸(CSSOM),然后出施工图(Layout),最后按图施工(Paint)并交付(Composite)。每一步职责清晰,层层递进。
回答时先给宏观框架(30 秒说出 7 个阶段),然后等对方追问某一步的细节。这展示了你的知识体系和沟通能力。不要一上来就背诵 DNS 的迭代查询细节。

Q2: URL 解析与导航开始

用户在地址栏输入内容后,浏览器做了什么?
浏览器首先判断输入的是搜索关键词还是 URL。如果包含 . 且没有空格,浏览器会补全协议(默认 https://)并开始导航。浏览器主进程(Browser Process)通过 IPC 通知网络进程(Network Process)发起请求,同时会触发 beforeunload 事件给当前页面,如果当前页面有未保存的表单数据,可以在此阶段拦截导航。 导航开始时,浏览器还会检查 HSTS(HTTP Strict Transport Security)列表,如果目标域名在列表中,会强制将 http:// 升级为 https://,避免中间人攻击。
HSTS 是服务器通过响应头 Strict-Transport-Security 告诉浏览器:“以后访问我必须用 HTTPS”。浏览器会把这个域名加入 HSTS 列表,下次访问时自动升级为 HTTPS,即使用户手动输入 http://。这可以防止 SSL 剥离攻击(中间人把 HTTPS 降级为 HTTP)。

Q3: DNS 解析:域名到 IP 的转换

浏览器怎么把 www.example.com 变成 93.184.216.34?
DNS 解析分两步:递归查询(浏览器到本地 DNS 服务器)和迭代查询(本地 DNS 到根/顶级域/权威 DNS)。 浏览器先查自身 DNS 缓存(chrome://net-internals/#dns 可查看),缓存 TTL 通常与 DNS 记录一致;再查操作系统缓存(getaddrinfo 系统调用)和 hosts 文件(/etc/hosts);最后由本地 DNS 服务器(通常由 ISP 或 8.8.8.8 等公共 DNS 提供)执行迭代查询。
DNS 默认用 UDP(端口 53),响应超过 512 字节时切换 TCP。DNSSEC 签名响应通常超过 512 字节,所以 DNSSEC 环境下几乎总是走 TCP。Chrome 还支持 DNS-over-HTTPS(DoH),将 DNS 查询封装在 HTTPS 请求中,防止 DNS 劫持。

DNS 缓存机制

DNS 解析结果会被缓存在多个层级: 浏览器查询 DNS 时,先查浏览器缓存,再查操作系统缓存和 hosts 文件,最后才问本地 DNS 服务器。如果本地 DNS 服务器有缓存且未过期,直接返回,不需要迭代查询。

DNS 劫持和 DNS-over-HTTPS

DNS 劫持是指攻击者篡改 DNS 解析结果,把用户引导到恶意网站。常见手段:运营商 DNS 劫持、中间人攻击、路由器劫持。 DNS-over-HTTPS(DoH)将 DNS 查询封装在 HTTPS 请求中,加密传输,防止中间人篡改。Chrome 从 2020 年开始默认启用 DoH(chrome://settings/security → 使用安全 DNS)。
DNS 解析就像查电话簿:先查自己的手机通讯录(浏览器缓存),没有就打 114(本地 DNS),114 再帮你查黄页(根 DNS),最后找到具体的电话号码(权威 DNS)。如果 114 也不知道,它会一层层往上问,直到找到答案。

Q4: TCP 三次握手与 TLS 握手

客户端和服务器怎么建立连接?
TCP 三次握手的目的是同步初始序列号并确认收发能力。客户端发送 SYN(Seq=x),服务器回复 SYN+ACK(Seq=y, Ack=x+1),客户端发送 ACK(Ack=y+1),双方确认能互相收发数据。 HTTPS 场景下还需要 TLS 握手。TLS 1.2 需要 2-RTT(先协商加密套件和密钥,再交换证书验证身份),TLS 1.3 优化为 1-RTT(将密钥交换和证书验证合并到同一批消息),还支持 0-RTT 恢复(通过 Pre-Shared Key 在第一个数据包中就携带应用数据,但有重放攻击风险)。 QUIC(HTTP/3)将传输层握手和 TLS 1.3 握手合并为一个过程,首次连接只需 1-RTT,恢复连接只需 0-RTT,彻底消除了”先建 TCP 连接再建 TLS 连接”的两步延迟。
TCP 三次握手就像打电话确认对方能听到:你拨号说”喂,能听到吗?“(SYN),对方接听说”能听到,你呢?“(SYN+ACK),你说”我也能听到”(ACK)——双方都确认能听到对方,通话建立。TLS 握手就像在通话前先约定暗号——双方确认用什么加密方式,验证对方身份。

为什么不能两次握手?

两次握手的问题是:服务器回复 SYN+ACK 时,客户端还没确认自己能收到服务器的数据。如果只握手两次,服务器不知道客户端能不能收到自己的回复,可能导致服务器单方面建立连接——客户端根本没收到服务器的响应,但服务器以为连接已建立,白白浪费资源。 三次握手的第三步(ACK)让服务器确认客户端能收到自己的回复,双方都确认收发能力后才建立连接。

TCP 四次挥手的过程

为什么是四次而不是三次?因为 TCP 是全双工的——关闭发送通道和接收通道是独立的操作。服务器收到客户端的 FIN 时,可能还有数据没发完,所以先回 ACK 确认收到,等数据发完再发 FIN。

TLS 1.2 和 1.3 的区别

TLS 1.3 的核心优化是将密钥交换和证书验证合并到同一批消息——客户端在 ClientHello 时就附带 DH 密钥共享,服务器在 ServerHello 时就完成密钥交换。这减少了 1 个 RTT。

0-RTT 恢复的风险

什么是 RTT? RTT(Round-Trip Time)是数据从客户端到服务器再回来的时间。一个 RTT 大约 50-200ms(取决于距离)。TLS 握手需要 1-2 个 RTT,意味着每次 HTTPS 连接要多等 100-400ms。 什么是 0-RTT? 0-RTT 是 TLS 1.3 的特性——客户端在第一个数据包中就携带应用数据,不需要等服务器回复。就像你打电话时,不等对方接就直接说”帮我订一杯咖啡”,对方接起电话就听到了,省了一个来回的时间。 风险是什么? 攻击者可以截获你的 0-RTT 数据包,复制一份发给服务器。服务器无法区分是新请求还是重放的旧请求——如果你发的是”转 100 元”,攻击者重放一次就多转了 100 元。 所以: 0-RTT 只适合幂等操作(GET 请求,重复执行结果一样),不适合敏感操作(POST、支付、转账)。

Q5: HTTP 请求与服务器响应

浏览器和服务器之间怎么交换数据?
浏览器发送 HTTP 请求报文,包含请求行(方法 + 路径 + 协议版本)、请求头(Cookie、Accept、Accept-Encoding、User-Agent 等)和可选的请求体;服务器处理后返回响应(状态码 + 响应头 + 响应体),响应头中的 Content-Type 决定浏览器如何解析响应体(text/html 走渲染流程,application/json 走 JS 处理)。HTTP/1.1 曾提出管线化(pipelining),但响应必须按请求顺序返回,且主流浏览器默认关闭,实际并未解决队头阻塞。
HTTP/2 的多路复用解决了 HTTP 层的队头阻塞,但 TCP 层的队头阻塞仍在——一个 TCP 包丢失会阻塞该连接上所有流。HTTP/3 用 QUIC(基于 UDP)为每个 Stream 独立处理丢包,彻底解决了这个问题。
HTTP/1.1 是一次只能发一个快递,发完才能发下一个(队头阻塞)。HTTP/2 是一辆卡车装多个快递,但一个坏了全车等(TCP 层阻塞)。HTTP/3 是每个快递独立运输,一个坏了不影响其他(QUIC/UDP)。

HTTP 缓存策略:强缓存 vs 协商缓存

浏览器缓存分为强缓存(不发请求,直接用缓存)和协商缓存(发请求问服务器,服务器说用缓存就用缓存)。
ETag vs Last-Modified:ETag 基于内容哈希,精确到字节级别;Last-Modified 基于修改时间,精度只到秒。ETag 优先级更高——如果同时存在,浏览器优先用 ETag。

HTTP 状态码详解

跨域解决方案(CORS)

浏览器的同源策略限制了跨域请求。CORS(Cross-Origin Resource Sharing)是 W3C 标准的跨域解决方案:
fetch 请求默认不携带 Cookie。如果需要携带 Cookie,必须设置 credentials: 'include',且服务器必须返回 Access-Control-Allow-Credentials: true。此时 Access-Control-Allow-Origin 不能是 *,必须是具体的域名。

Q6: 浏览器解析:从字节流到渲染树

浏览器拿到 HTML 字节后,怎么变成可以渲染的树结构?
HTML 解析器采用增量解析(边下载边解析),将字节流先 Tokenize 为 Token(开始标签、结束标签、文本节点),再由 TreeBuilder 构建 DOM 树。CSS 解析器独立构建 CSSOM 树,两者合并为渲染树(Render Tree)。 渲染树排除 display:none 的节点(不在渲染树中),但保留 visibility:hidden 的节点(在渲染树中但不绘制)。伪元素(::before/::after)在渲染树中生成匿名节点。
CSS 文件加载完成前,CSSOM 没就绪,渲染树无法构建,页面不会渲染。但 CSS 不阻塞 DOM 解析——HTML 解析器可以继续构建 DOM 树,只是不能渲染。JS 会阻塞 DOM 解析——浏览器遇到 <script> 标签时会暂停 HTML 解析,等待 JS 下载并执行完毕。
DOM 树就像建筑的骨架图纸(结构),CSSOM 树就像装修图纸(样式)。两张图纸合并后才是完整的施工图(渲染树)。如果装修图纸还没画好(CSS 没加载完),施工队(渲染引擎)就无法开工——但可以先搭骨架(DOM 解析继续)。

CSS 阻塞渲染的优化策略

CSS 阻塞渲染是因为浏览器需要 CSSOM 才能构建渲染树。优化策略:
  • 内联关键 CSS:把首屏需要的 CSS 内联到 <style> 标签中(控制在 14KB 以内,匹配 TCP 初始拥塞窗口)
  • 异步加载非关键 CSS:用 <link rel="preload" as="style" onload> 异步加载非首屏 CSS
  • CSS 放 <head>:尽早开始下载,不要放在 <body> 底部

JS 阻塞 DOM 解析的优化策略

JS 阻塞 DOM 解析是因为 JS 可能调用 document.write() 重写文档,或者访问已解析的 DOM 节点。优化策略:
  • defer:不阻塞 DOM 解析,DOM 解析完后按文档顺序执行(推荐)
  • async:不阻塞 DOM 解析,下载完立即执行(适合独立脚本)
  • type="module":默认 defer 行为,按依赖图顺序执行

渲染树和 DOM 树的区别

渲染树是 DOM 树和 CSSOM 树的合并结果。display:none 的节点不在渲染树中(不占位),visibility:hidden 的节点在渲染树中(占位但不绘制)。

Q7: 渲染流程:Layout → Paint → Composite

渲染树构建完成后,怎么变成屏幕上的像素?
Layout(布局/重排):计算每个节点的精确几何信息(位置、大小、边距)。盒模型计算在此阶段完成——content + padding + border + margin。Flexbox/Grid 布局的子元素分配也在此阶段。输出是 Layout Tree(带几何信息的渲染树)。 Paint(绘制):将渲染树转化为绘制指令列表(Paint Records)。按 Stacking Context 规则生成绘制指令——背景、边框、浮动、行内元素、定位元素,从低到高依次绘制。 Composite(合成):由 GPU 合成器将多个图层(Composited Layers)合并为最终画面。transform 和 opacity 动画在此阶段执行,不需要重排重绘,性能最好。
重排(Reflow)需要重新计算布局,代价最高——影响当前节点及其所有子节点。重绘(Repaint)只需要重新生成绘制指令,代价较低。合成(Composite)只需要 GPU 矩阵变换,代价最低。优化策略:尽量用 transform/opacity 做动画,避免触发布局属性变化。
Layout 就像施工队量房间尺寸、算家具位置(几何计算)。Paint 就像按图纸刷墙、铺地板(绘制指令)。Composite 就像最后的软装——把家具摆好、挂上窗帘(GPU 合成)。如果只是换个窗帘颜色(opacity 变化),不需要重新量房间(重排),直接换就行。

重排(Reflow)的触发条件

重排需要重新计算节点的几何信息,代价最高。触发条件:
  • DOM 增删(插入/删除节点)
  • 元素尺寸变化(width、height、padding、margin、border)
  • 内容变化(文本增减、图片尺寸变化)
  • 浏览器窗口 resize
  • 读取布局属性(offsetWidth、offsetHeight、getComputedStyle、getBoundingClientRect)
读取布局属性(如 offsetWidth)后立即修改样式,会触发强制同步布局——浏览器必须先完成之前的样式修改,才能返回准确的布局信息。这会导致一帧内多次重排,性能极差。

重绘(Repaint)的触发条件

重绘只需要重新生成绘制指令,不影响布局,代价较低。触发条件:
  • 颜色变化(color、background-color、border-color)
  • 阴影变化(box-shadow、text-shadow)
  • 可见性变化(visibility、outline)
  • 文本装饰变化(text-decoration)

Composite 阶段的优化

合成阶段由 GPU 执行,只需要矩阵变换,不需要重排重绘。触发合成的操作:
  • transform(位移、缩放、旋转)
  • opacity(透明度)
  • will-change(提前告知浏览器哪些属性会变化)
优化策略:用 transform 做位移/缩放/旋转动画,用 opacity 做透明度动画,避免触发布局属性(width、height、margin、padding)变化。

Q8: script 标签的加载方式有什么区别?

async 脚本下载完就执行,不保证顺序——如果页面有两个 async 脚本,谁先下载完谁先执行。defer 脚本在 DOM 解析完成后按文档顺序执行——保证顺序。大多数业务脚本应该用 defer,独立脚本(如统计 SDK)可以用 async。

底层源码:Chromium 是如何实现的?

Blink 的渲染流水线在 LocalFrame::ScheduleVisualUpdate() 中触发一帧渲染(详见 Blink 源码 local_frame.cc)。每一帧的执行顺序是:
  1. Style Calculation:计算每个节点的最终样式(StyleEngine::RecalcStyle())
  2. Layout:计算几何信息(LayoutView::Layout())
  3. Paint:生成绘制指令(PaintController::Paint())
  4. Composite:GPU 合成(LayerTreeHost::Composite())
DOM 树包含所有节点(包括 display:none 的节点),渲染树只包含可见节点。渲染树是 DOM 树和 CSSOM 树的合并结果,每个节点都有计算后的完整样式信息。详见 Blink 源码 style_engine.cc。

及格回答 vs 满分回答

问题:“从输入 URL 到页面展示,发生了什么?”

及格回答(60-70分):
“浏览器先做 DNS 解析,然后建立 TCP 连接,发送 HTTP 请求,服务器返回 HTML,浏览器解析 HTML 构建 DOM 树,再解析 CSS 构建 CSSOM 树,两者合并为渲染树,然后 Layout、Paint、Composite,最终显示在屏幕上。”
问题出在:背了流程但不理解每一步的细节。 满分回答(90-100分):
从输入 URL 到页面展示,浏览器要经历 7 个阶段。首先是网络阶段:URL 解析(补全协议、检查 HSTS)、DNS 解析(浏览器缓存 → 操作系统缓存 → 本地 DNS 迭代查询)、TCP 三次握手(SYN → SYN+ACK → ACK)、TLS 握手(TLS 1.3 优化为 1-RTT,支持 0-RTT 恢复)、HTTP 请求/响应(HTTP/2 多路复用解决 HTTP 层队头阻塞,HTTP/3 用 QUIC 解决 TCP 层队头阻塞)。Tali Garsiel 和 Paul Irish 在经典文章《How Browsers Work》中首次系统性地将浏览器内部分为解析、渲染、合成三大模块,为后续所有浏览器原理文章奠定了框架基础。[1]
然后是渲染阶段:HTML 解析器采用增量解析(边下载边解析),将字节流 Tokenize 为 Token,再由 TreeBuilder 构建 DOM 树;CSS 解析器独立构建 CSSOM 树,两者合并为渲染树(排除 display:none 的节点)。Layout 阶段计算每个节点的精确几何信息(盒模型、Flexbox/Grid 子元素分配),Paint 阶段按 Stacking Context 规则生成绘制指令列表,Composite 阶段由 GPU 合成器将多个图层合并为最终画面。李兵在极客时间《浏览器工作原理与实践》中将渲染流水线拆解为 Style Calculation → Layout → Paint → Composite 四个阶段,并指出 Chrome 为每帧分配约 16.6ms,其中 JS 执行约 5ms、渲染约 11ms,这个时间分配直接影响动画流畅度。[2]
渲染阶段有两个关键的性能陷阱:一是 CSS 阻塞渲染但不阻塞 DOM 解析——CSS 文件加载完成前,渲染树无法构建,页面不会渲染,但 HTML 解析器可以继续构建 DOM 树。二是 JS 阻塞 DOM 解析——浏览器遇到 <script> 标签时会暂停 HTML 解析,等待 JS 下载并执行完毕。优化策略:CSS 放 <head> 尽早加载,JS 用 defer 避免阻塞 DOM 解析,transform/opacity 动画走合成器不走主线程。[3]

常见追问

答题要点: CSS 不阻塞 DOM 解析但阻塞渲染,JS 阻塞 DOM 解析。高分回答: “CSS 不阻塞 DOM 解析——HTML 解析器可以继续构建 DOM 树,只是不能渲染(因为 CSSOM 没就绪,渲染树无法构建)。JS 阻塞 DOM 解析——浏览器遇到 <script> 标签时会暂停 HTML 解析,等待 JS 下载并执行完毕。
这是因为 JS 可能调用 document.write() 重写文档,或者通过 document.querySelector 访问已解析的 DOM 节点,浏览器无法预知脚本行为,只能保守地暂停。”
答题要点: CRP 是从收到 HTML 到首次渲染的路径,优化关键是减少关键资源数量和缩短关键路径长度。高分回答: “关键渲染路径(Critical Rendering Path)是从收到 HTML 到首次渲染的路径:HTML → DOM → CSSOM → 渲染树 → Layout → Paint。优化策略:1) 内联关键 CSS(控制在 14KB 以内,匹配 TCP 初始拥塞窗口);2) 延迟非关键 CSS 用 <link rel='preload' as='style' onload> 异步加载;3) JS 用 defer 避免阻塞 DOM 解析;4) SSR/SSG 直出 HTML 让浏览器立即开始解析。”
答题要点: 重排是重新计算布局,重绘是重新生成绘制指令。重排比重绘代价高得多。高分回答: “重排(Reflow)需要重新计算节点的几何信息(位置、大小),影响当前节点及其所有子节点,代价最高。重绘(Repaint)只需要重新生成绘制指令,不影响布局,代价较低。减少重排的方法:1) 批量修改样式(用 class 一次性改);2) 避免读取布局属性(offsetWidth、getComputedStyle)后立即修改样式(会触发强制同步布局);3) 用 transform/opacity 做动画,走合成器不走主线程。”
答题要点: 不一定。HTTP/2 解决了 HTTP 层的队头阻塞,但 TCP 层的队头阻塞仍在。高分回答: “不一定。HTTP/2 的多路复用解决了 HTTP 层的队头阻塞,但 TCP 层的队头阻塞仍在——一个 TCP 包丢失会阻塞该连接上所有流。在高丢包率的网络环境下(如移动网络),HTTP/2 可能比 HTTP/1.1 更慢,因为 HTTP/1.1 的 6 个连接是独立的,一个连接丢包不影响其他连接。HTTP/3 用 QUIC(基于 UDP)为每个 Stream 独立处理丢包,彻底解决了这个问题。”
答题要点: 浏览器到本地 DNS 是递归查询,本地 DNS 到根/权威 DNS 是迭代查询。高分回答: “递归查询是’我帮你查到底’——浏览器问本地 DNS,本地 DNS 负责从根 DNS 一直问到权威 DNS,最后把结果返回给浏览器。迭代查询是’我告诉你下一步问谁’——根 DNS 不直接查,而是告诉本地 DNS ‘你去问 .com DNS’,本地 DNS 再问 .com DNS,.com DNS 说’你去问 example.com 权威 DNS’,最后权威 DNS 返回结果。浏览器到本地 DNS 是递归查询,本地 DNS 到根/权威 DNS 是迭代查询。”
答题要点: 三次握手同步初始序列号并确认收发能力,四次挥手确保双方数据都发完。高分回答: “三次握手:客户端发 SYN(Seq=x),服务器回 SYN+ACK(Seq=y, Ack=x+1),客户端发 ACK(Ack=y+1)。为什么不能两次?因为服务器回复 SYN+ACK 时,客户端还没确认自己能收到服务器的数据——如果只握手两次,服务器不知道客户端能不能收到自己的回复,可能导致服务器单方面建立连接。四次挥手:客户端发 FIN,服务器回 ACK(此时服务器可能还有数据没发完),服务器发 FIN,客户端回 ACK。为什么是四次而不是三次?因为 TCP 是全双工的——关闭发送通道和接收通道是独立的操作。”
答题要点: TLS 1.2 需要 2-RTT,TLS 1.3 优化为 1-RTT,支持 0-RTT 恢复。高分回答: “TLS 1.2 握手:客户端发 ClientHello(支持的加密套件列表),服务器回 ServerHello(选定的加密套件)+ 证书,客户端验证证书 + 交换密钥,双方生成会话密钥。需要 2-RTT。TLS 1.3 优化:将密钥交换和证书验证合并到前两条消息,客户端在 ClientHello 时就附带 DH 密钥共享,服务器在 ServerHello 时就完成密钥交换。只需 1-RTT。还支持 0-RTT 恢复——通过 Pre-Shared Key 在第一个数据包中就携带应用数据,但有重放攻击风险。”
答题要点: Composite 阶段由 GPU 合成器执行,只需要矩阵变换,不需要重排重绘。高分回答: “Composite 阶段由 GPU 合成器将多个图层(Composited Layers)合并为最终画面。当元素被提升为独立图层后(通过 will-change 或 transform),后续的 transform/opacity 变化只需要 GPU 做矩阵变换,不需要重排(Layout)也不需要重绘(Paint)。
优化策略:用 transform 做位移/缩放/旋转动画,用 opacity 做透明度动画,避免触发布局属性(width、height、margin、padding)变化。“

延伸阅读与引用参考

  • How Browsers Work:Tali Garsiel & Paul Irish 的经典文章,系统梳理了解析、渲染树、布局与绘制的完整流程,是浏览器原理文章的重要参考。[1]
  • High Performance Browser Networking:Ilya Grigorik 的免费在线书籍,涵盖 DNS、TCP、TLS、HTTP 全链路优化,是网络层性能优化的权威参考。[2]
  • Inside look at modern web browser:Lin Clark 在 Chrome Developers 发表的四部曲系列(2018),用漫画解析 Chromium 多进程架构、渲染流水线和合成器工作原理。
  • 李兵 极客时间《浏览器工作原理与实践》:将渲染流水线拆解为 Style → Layout → Paint → Composite 四阶段,给出每帧 16.6ms 的时间分配模型(JS 5ms + 渲染 11ms)。
  • 《HTTP 图解》:上野宣著,用图解方式讲解 HTTP 协议的核心知识。
  • MDN Web Docs - 渲染性能:MDN 对浏览器渲染性能的权威指南。
  • Cloudflare Blog - HTTP/3:Cloudflare 对 HTTP/3 和 QUIC 协议的深度解析,含 0-RTT 恢复的安全风险分析。