第 6 章 · 浏览器工作原理

浏览器是前端代码的运行时:把 HTML/CSS 解析成像素、加载脚本、发请求。

6.1 渲染流水线

HTML ─解析→ DOM 树
CSS  ─解析→ CSSOM 树
           ↓ 合并
        渲染树(Render Tree)
           ↓
        布局 Layout(算每个盒子的几何位置,见第 2/3 章)
           ↓
        绘制 Paint(把盒子画成像素)
           ↓
        合成 Composite(分层合成上屏)
  • DOM 树描述结构(第 5 章),CSSOM描述样式,合并成渲染树(只含可见节点,display:none 不进入)。
  • 布局计算尺寸位置,绘制填充像素。
  • 合成把页面分层(transformopacity 触发 GPU 合成),改这些属性只重合成、不重排,动画最省。

6.2 回流 vs 重绘

回流 Reflow重绘 Repaint
触发几何属性变化(尺寸/位置/内容)仅视觉属性变化(颜色/背景/阴影)
代价高(重新布局 + 可能重绘)较低(只重画像素)
例子width、增删 DOM、读 offsetWidthcolorbackground
// 反例:读一次写一次,强制多次回流
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

6.3 JS 会阻塞渲染

HTML 解析遇到 <script> 会停下解析、先下载并执行脚本:

<script src="app.js"></script>       <!-- 阻塞:下载 + 执行都卡解析 -->
<script src="a.js" defer></script>   <!-- 下载不阻塞,DOM 解析完再按序执行 -->
<script src="b.js" async></script>   <!-- 下载完立即执行,不保证顺序 -->
阻塞解析执行时机顺序
普通 <script>是(下载+执行都卡)立即按出现顺序
deferDOM 解析完成后按出现顺序
async否(下载时)下载完立即不保证

对比:同步脚本阻塞解析(大脚本就白屏);defer 晚执行但保序,async 下载完就跑不保序。

6.4 与网络请求的关系

页面渲染通常被网络卡脖子,而非 CPU:

  1. 浏览器先发请求拿 HTML(DNS → TCP → TLS → HTTP,见「计算机网络」);
  2. 解析 HTML 时发现 <link>/<script>/<img>,并发发起子资源请求(HTTP/1.1 每域名约 6 个并发,HTTP/2 多路复用);
  3. 关键资源(CSS、同步脚本)阻塞首屏,所以要「内联首屏 CSS、defer 非关键脚本」。
  • 强缓存(Cache-Control)命中不请求,协商缓存(ETag/Last-Modified)命中少传体(见「计算机网络」)。
  • 这正是第 9 章工程化的目标:打包压缩、代码分割、CDN,本质都是减少网络往返、加快首屏。