浏览器是前端代码的运行时:把 HTML/CSS 解析成像素、加载脚本、发请求。
HTML ─解析→ DOM 树
CSS ─解析→ CSSOM 树
↓ 合并
渲染树(Render Tree)
↓
布局 Layout(算每个盒子的几何位置,见第 2/3 章)
↓
绘制 Paint(把盒子画成像素)
↓
合成 Composite(分层合成上屏)
display:none 不进入)。transform、opacity 触发 GPU 合成),改这些属性只重合成、不重排,动画最省。| 回流 Reflow | 重绘 Repaint | |
|---|---|---|
| 触发 | 几何属性变化(尺寸/位置/内容) | 仅视觉属性变化(颜色/背景/阴影) |
| 代价 | 高(重新布局 + 可能重绘) | 较低(只重画像素) |
| 例子 | 改 width、增删 DOM、读 offsetWidth | 改 color、background |
// 反例:读一次写一次,强制多次回流
for (let i = 0; i < 100; i++) {
el.style.width = i + "px"; // 写 → 回流
const w = el.offsetWidth; // 读 → 强制同步回流
}
// 正例:用文档片段批量插入,只回流一次
const frag = document.createDocumentFragment();
for (let i = 0; i < 100; i++) {
const node = document.createElement("div");
frag.appendChild(node);
}
container.appendChild(frag);
对比:回流必然伴随重绘,重绘不一定回流;回流代价远高。优化:批量改 DOM、读写分离、动画只用
transform/opacity。
HTML 解析遇到 <script> 会停下解析、先下载并执行脚本:
<script src="app.js"></script> <!-- 阻塞:下载 + 执行都卡解析 -->
<script src="a.js" defer></script> <!-- 下载不阻塞,DOM 解析完再按序执行 -->
<script src="b.js" async></script> <!-- 下载完立即执行,不保证顺序 -->
| 阻塞解析 | 执行时机 | 顺序 | |
|---|---|---|---|
普通 <script> | 是(下载+执行都卡) | 立即 | 按出现顺序 |
defer | 否 | DOM 解析完成后 | 按出现顺序 |
async | 否(下载时) | 下载完立即 | 不保证 |
对比:同步脚本阻塞解析(大脚本就白屏);
defer晚执行但保序,async下载完就跑不保序。
页面渲染通常被网络卡脖子,而非 CPU:
<link>/<script>/<img>,并发发起子资源请求(HTTP/1.1 每域名约 6 个并发,HTTP/2 多路复用);defer 非关键脚本」。Cache-Control)命中不请求,协商缓存(ETag/Last-Modified)命中少传体(见「计算机网络」)。