知

模块二 · 工程化与网络

第 6 / 14 节19 分钟阅读型

从输入 URL 到页面渲染:完整链路

一道题串起 DNS、TCP、TLS、HTTP 与浏览器渲染。这一节按时间顺序拆解每一跳,并指出每一跳能优化什么。

读完这一节,你能做到

  1. 按顺序说出从输入 URL 到首屏的每一跳。
  2. 判断一次慢请求卡在 DNS、连接、服务端还是渲染。
  3. 说清关键渲染路径的五个步骤。
  4. 用首屏指标定位优化点。

一、URL 解析与缓存查找

浏览器先解析 URL:协议、域名、端口、路径、查询参数。然后按顺序查找缓存:

Service Worker → Memory Cache → Disk Cache → 强缓存 → 协商缓存 → 网络

强缓存看 Cache-Control/Expires,命中就不发请求;协商缓存看 ETag/Last-Modified,命中返回 304,省掉响应体。

这一跳最常见的优化是给静态资源加长缓存 + 内容哈希,把"重复下载"变成"直接命中"。

二、DNS 与连接

  • DNS:域名解析成 IP。优化手段是 DNS 预解析(dns-prefetch)与减少域名数量。
  • TCP:三次握手建立连接。HTTP/1.1 有连接数限制,HTTP/2 多路复用,HTTP/3 用 QUIC 减少握手。
  • TLS:HTTPS 需要 TLS 握手,会多出 1-2 个 RTT;会话复用与 TLS 1.3 能减少开销。
<link rel="dns-prefetch" href="//cdn.example.com" />
<link rel="preconnect" href="https://cdn.example.com" crossorigin />

预连接适合"确定马上要用"的域名,不要给所有域名都加,反而浪费连接。

三、HTTP 请求与响应

请求发出后,服务端处理并返回响应。需要关注:

部分关注点
状态码200/301/304/401/500 分别对应什么
响应头缓存、压缩、CORS、安全策略
响应体HTML 大小、是否启用 gzip/brotli
首字节TTFB 反映服务端与网络延迟

TTFB 高通常是服务端或网络问题,不是前端能解决的;这时优化前端资源没有意义。

四、浏览器进程模型

现代浏览器是多进程架构:

  • 浏览器进程:地址栏、标签页管理。
  • 渲染进程:每个标签页一个,负责 HTML/CSS/JS 执行与渲染。
  • GPU 进程:合成与绘制。
  • 网络进程:请求与缓存。

渲染进程内的主线程同时负责 JS、样式、布局与绘制,所以长任务会阻塞渲染——这也是"事件循环"和"性能优化"的连接点。

五、关键渲染路径

HTML → DOM
CSS  → CSSOM
DOM + CSSOM → Render Tree → Layout → Paint → Composite

五个关键结论:

  1. CSS 是阻塞渲染的:没有 CSSOM,浏览器不会绘制。
  2. JS 是阻塞解析的(未加 async/defer 时):脚本会打断 HTML 解析。
  3. 布局与绘制在主线程,合成可以在合成线程。
  4. transform/opacity 通常只触发合成,成本低;改宽高会触发布局。
  5. 图片要预留尺寸,否则会引起布局偏移(CLS)。

六、首屏指标与优化

指标反映优化方向
TTFB服务端与网络缓存、CDN、后端
FCP首次内容绘制阻塞资源、字体
LCP最大内容绘制图片、关键 CSS
TBT主线程阻塞拆长任务、减少 JS
CLS布局偏移预留尺寸

一个实用顺序:先看 Network 瀑布图找"最慢的一跳",再看 Performance 找长任务,最后才谈代码拆分。

一次慢首屏的排查案例

某后台首屏 5.2 秒。Network 显示:HTML TTFB 1.8 秒、一个同步脚本 1.1MB、首屏接口串行 1.2 秒。

处理顺序:

  1. 服务端加缓存,TTFB 降到 300ms。
  2. 脚本改 defer + 路由分包,阻塞时间降到 200ms。
  3. 首屏接口并行化,并加骨架屏。

结果 1.9 秒。代价是首屏多了一次加载态,且服务端需要维护缓存失效。

这个案例说明:首屏慢通常不是单一原因,要按“网络 → 资源 → 接口”的顺序拆。

关键请求链

浏览器会为关键资源排优先级:HTML 最高,CSS 次之,字体与首屏图片再次。preload 可以提升发现晚的关键资源,但会抢占带宽;prefetch 是空闲时预取下一页,优先级最低。

判断标准:这个资源是否“首屏必须且发现得晚”。是,才 preload。

关键渲染路径的两条优化线

第一条是“少阻塞”:CSS 内联关键部分、脚本加 defer、字体用 font-display: swap。

第二条是“早发现”:用 preload/preconnect 提前建立连接、提前拉取关键资源;用 103 Early Hints 让浏览器在服务端思考时就预加载。

两条线的目标相同:让首屏需要的东西更早到、更少排队。不要只做其中一条。

一次请求的耗时拆解

拿到瀑布图后,把一次请求拆成:排队 → DNS → 连接 → TLS → TTFB → 下载。哪一段最长,优化就落在哪:

  • 排队/连接长:连接未复用、域名太多。
  • TTFB 长:服务端或网络。
  • 下载长:体积、压缩、带宽。

拆完再谈手段,比背清单更有效。

七、常见坑

  1. 所有资源都加 preload,反而抢了关键资源带宽。
  2. CSS 放底部或用 JS 注入,导致白屏时间变长。
  3. 同步脚本放 head,阻塞解析。
  4. 只优化包体,不优化 TTFB。
  5. 图片没有宽高,造成 CLS。

八、动手任务:自写 → AI 写 → 对比 → 取舍

四步不跳:① 自己写(限时,关掉补全)→ ② 让 AI 写同一题 → ③ 逐条比对 → ④ 说出保留谁的写法。 完整动作与记录模板见《AI 协作与代码评审》。

① 自己写

  1. 用 Network 面板记录一次首屏,标出 DNS、连接、TTFB、下载各占多少。
  2. 给一个页面加 preconnect 与 dns-prefetch,对比首屏。
  3. 用 Lighthouse 跑一次,列出三个最值得改的项。

② 让 AI 写同一题

把第 2 题(复述整条链路)交给 AI,要求每一步都写出“这一步花的时间由什么决定”。

③ 对比要盯的点

  • DNS、TCP、TLS、首字节的先后顺序它写对了吗?
  • 强缓存命中发生在哪一步?它有没有把缓存和 DNS 的顺序搞混?
  • DOMContentLoaded 与 load 的区别它讲清了吗?前者不等图片。

④ 一句话取舍

它给的链路里,哪一步在你这项目上其实被跳过了?

九、自测

  1. 浏览器缓存的查找顺序是什么?
  2. 强缓存与协商缓存的区别?
  3. 关键渲染路径的五个步骤?
  4. 为什么 CSS 阻塞渲染、JS 阻塞解析?
  5. TTFB 高应该优化前端吗?

参考答案要点:SW→内存→磁盘→强缓存→协商;是否发请求/304;DOM/CSSOM/Render/Layout/Paint;构建树与脚本执行;先查服务端与网络。

附录:高频追问

问:输入 URL 后第一件事是什么? 解析 URL 并查缓存,不是直接发请求;命中强缓存可能完全不联网。

问:DNS 解析用 TCP 还是 UDP? 通常 UDP,响应过大或区域传送时用 TCP;HTTP/3 下 DNS 也可能走 DoH。

问:HTTP/2 解决了什么? 多路复用、头部压缩、服务端推送(已弱化),解决 HTTP/1.1 的队头阻塞与连接数限制。

问:HTTP/3 为什么更快? 基于 QUIC(UDP),减少握手次数,解决 TCP 层的队头阻塞。

问:defer 和 async 的区别? defer 保证顺序、在 DOMContentLoaded 前执行;async 下载完就执行,顺序不确定。

问:为什么 CSS 要放 head? 尽早构建 CSSOM,避免白屏与无样式闪烁。

问:首屏优化先做什么? 先测量:TTFB、LCP、阻塞资源,再决定是网络、服务端还是渲染问题。

问:预加载会拖慢首屏吗? 会。preload 优先级高,抢关键资源带宽;只给真正关键且发现晚的资源用。

配套题目

★ 越多越该先背;点题目可看完整答案与深入版。

提示:读完可以顺手做几道对应题目,检验是否真的理解