从 URL 到页面渲染完整流程
📚 相关文档
- DNS 域名解析原理与优化 - DNS 查询、缓存、优化详解
- TCP 三次握手与四次挥手 - 握手流程、TIME_WAIT、SYN Flood 防御
- HTTP/1.1 vs HTTP/2 - 协议对比、多路复用、队头阻塞
一、整体流程概览
``mermaid graph TD A[用户输入 URL] --> B[URL 解析] B --> C[DNS 解析] C --> D[TCP 握手] D --> E{HTTPS?} E -->|是| F[TLS 握手] E -->|否| G[发送 HTTP 请求] F --> G G --> H[服务器响应] H --> I[解析 HTML → DOM] I --> J[解析 CSS → CSSOM] J --> K[生成 Render Tree] K --> L[布局 Layout] L --> M[绘制 Paint] M --> N[合成 Composite] N --> O[屏幕显示]
style A fill:#e1f5ff
style O fill:#d4edda
style F fill:#fff3cd
**时间分配参考**:
- DNS + TCP + TLS:~100-300ms
- 服务器响应:~50-500ms
- **前端渲染:~100-2000ms**(优化重点)
---
## 二、网络阶段(简述)
::: info 💡 详细说明请查看专项文档
以下阶段在独立文档中深入讲解,此处仅概述流程。
:::
### 1. DNS 解析
将域名转换为 IP 地址,经过多级缓存(浏览器 → 系统 → ISP → 权威 DNS)。
👉 详细原理:[DNS 域名解析原理与优化](./03.DNS 域名解析原理与优化.md)
### 2. TCP 握手
建立可靠连接(三次握手),确保双方收发能力正常。
👉 详细原理:[TCP 三次握手与四次挥手](./04.TCP 三次握手与四次挥手.md)
### 3. TLS 握手(HTTPS)
- **TLS 1.2**:2-RTT
- **TLS 1.3**:1-RTT(优化)
- **0-RTT**:会话恢复模式
### 4. HTTP 请求与响应
**请求报文**:
```http
GET /path HTTP/1.1
Host: www.example.com
User-Agent: Mozilla/5.0...
Accept: text/html
Cookie: session_id=abc123响应报文:
http
HTTP/1.1 200 OK
Content-Type: text/html; charset=utf-8
Cache-Control: max-age=3600
ETag: "abc123"
<!DOCTYPE html>...三、渲染阶段(核心)
1. 关键渲染路径(CRP)
``mermaid graph TB A[HTML] --> B[构建 DOM 树] C[CSS] --> D[构建 CSSOM 树] B --> E[合并生成 Render Tree] D --> E E --> F[布局 Layout] F --> G[绘制 Paint] G --> H[合成 Composite] H --> I[栅格化 Rasterize] I --> J[GPU 上屏]
style A fill:#ffe6e6
style C fill:#e6f3ff
style J fill:#d4edda
### 2. 构建 DOM 树
**特点**:
- ✅ **增量构建**:边下载边解析
- ✅ **预加载扫描器**:遇到 `<img>`、`<link>` 提前发起请求
- ⚠️ **阻塞行为**:`<script>` 会阻塞解析(除非 `async/defer`)
```html
<!DOCTYPE html>
<html>
<head>
<link rel="stylesheet" href="style.css"> <!-- 不阻塞解析,但阻塞渲染 -->
</head>
<body>
<div class="container">
<h1>Hello</h1>
</div>
<script src="app.js"></script> <!-- 阻塞解析 -->
</body>
</html>3. 构建 CSSOM 树
特性:
- 层叠性:多个规则按优先级合并
- 继承性:
color、font-size等从父元素继承 - 计算值:相对单位(
em、%)转为绝对单位(px)
4. 生成 Render Tree
合并 DOM + CSSOM,排除不可见元素:
排除:
<script>、<meta>、<link>display: none的元素
保留:
visibility: hidden(仍占空间)opacity: 0(仍参与渲染)
5. 布局(Layout / Reflow)
计算每个元素的精确位置和尺寸。
触发布局的操作:
| 操作 | 说明 |
|---|---|
| 首次加载 | 必然触发 |
| 窗口大小变化 | 重新计算 |
修改 width/height/margin | 影响几何属性 |
| 添加/删除 DOM 节点 | 影响周围元素 |
读取 offsetWidth | 强制同步布局 |
性能优化:
- ✅ 批量修改样式,避免多次重排
- ✅ 使用
transform替代top/left(不触发布局) - ❌ 避免"布局抖动"(读写交替)
6. 绘制(Paint)
将渲染树转换为实际像素。
过程:
- 分层:划分为多个图层(Layer)
- 生成绘制指令:为每个图层生成命令
- 光栅化:矢量图形 → 位图
触发绘制的操作:
- 修改颜色、背景、边框、阴影
- 添加/删除元素
优化:
- 减少复杂效果(渐变、模糊)
- 使用
will-change提示浏览器
7. 合成(Composite)
将多个图层叠加形成最终画面。
优势:
- ✅ 独立更新:某图层变化只需重新合成该层
- ✅ GPU 加速:利用并行计算
- ✅ 动画流畅:
transform/opacity跳过布局和绘制
触发合成的操作:
transform(平移、旋转、缩放)opacity(透明度)
性能优化:
- ✅ 动画使用
transform/opacity(保证 60 FPS) - ✅
position: fixed/sticky创建独立图层 - ✅ 合理使用
will-change: transform
四、性能优化关键点
1. 首屏优化实战
① 关键资源优先级
html
<!-- 高优先级 -->
<link rel="preload" href="critical.css" as="style">
<link rel="preload" href="hero-image.webp" as="image">
<!-- 低优先级 -->
<link rel="prefetch" href="analytics.js" as="script">② 内联关键 CSS
html
<head>
<style>
/* Critical CSS: Header + Hero */
header { height: 60px; }
.hero { display: flex; }
</style>
<link rel="stylesheet" href="non-critical.css" media="print" onload="this.media='all'">
</head>③ 延迟加载 JS
html
<script src="app.js" defer></script>
<script src="analytics.js" async></script>④ 图片优化
html
<img
src="image-800w.webp"
srcset="image-400w.webp 400w, image-800w.webp 800w"
loading="lazy"
decoding="async"
>2. 性能监控指标
| 指标 | 全称 | 优秀标准 | 工具 |
|---|---|---|---|
| FCP | First Contentful Paint | < 1.8s | Lighthouse |
| LCP | Largest Contentful Paint | < 2.5s | Web Vitals |
| FID | First Input Delay | < 100ms | Performance API |
| CLS | Cumulative Layout Shift | < 0.1 | Web Vitals |
五、面试标准回答
从输入 URL 到页面渲染主要经历:
- 网络阶段:DNS 解析 → TCP 握手 → TLS 握手(HTTPS)→ 发送 HTTP 请求 → 接收响应
- 渲染阶段:解析 HTML 构建 DOM → 解析 CSS 构建 CSSOM → 合并生成 Render Tree → 布局(Layout)→ 绘制(Paint)→ 合成(Composite)→ 上屏显示
前端优化重点在渲染阶段:
- 提取关键 CSS 内联,异步加载非关键 CSS
- JS 使用
defer/async避免阻塞解析- 动画使用
transform/opacity跳过布局和绘制- 图片懒加载、WebP 格式、响应式图片
六、高频追问
Q1: 什么是重排(Reflow)和重绘(Repaint)?
答:
- 重排:元素几何属性改变,需重新计算布局(成本高)
- 重绘:视觉属性改变,只需重新绘制像素(成本低)
- 关系:重排必触发重绘,重绘不一定触发重排
避免策略:
- 使用
transform替代top/left - 批量修改样式
- 动画元素设置
position: absolute/fixed
Q2: 为什么 <script> 放在 <body> 底部?
答:
<script>会阻塞 HTML 解析- 放底部确保 DOM 基本构建完成,避免白屏
- 现代方案:使用
defer(DOM 解析完后执行)或async(下载完立即执行)
Q3: 如何优化首屏加载速度?
答:
- 减少请求:合并、雪碧图、缓存
- 减小体积:Gzip/Brotli 压缩、Tree Shaking
- 加快速度:CDN、HTTP/2、预加载
- 优化渲染:关键 CSS 内联、JS 延迟、transform 动画
七、总结记忆口诀
📝 URL 解析查安全
🔍 DNS 寻址找 IP
🤝 TCP 握手建连接
🔐 TLS 协商加密钥
📤 发送请求等响应
🌳 构建 DOM 和 CSSOM
🎨 渲染树上布局绘
✨ 合成栅格显屏幕核心优化思路:
- 减少请求、减小体积、加快速度、优化渲染