Skip to main content

浏览器的工作原理

多进程架构

现代浏览器采用 多进程 架构以提高安全性、稳定性和性能。多进程架构将页面隔离,避免单个页面崩溃拖垮整个浏览器。渲染进程运行在受限的沙箱中,即便执行恶意脚本也不会直接危及操作系统安全。

浏览器进程

负责 UI 渲染、用户交互、标签页管理、网络进程的调度等,它是整个浏览器的大脑。

渲染进程

每个页面通常在独立的渲染进程中运行。渲染进程内部包含 HTML/CSS 解析、V8 JavaScript 引擎、布局引擎、图层管理等组件,用于将网页内容呈现为像素。

网络进程

统一处理所有网络请求(HTTP/2、HTTP/3、TLS 等),下载资源后分发给渲染进程。网络进程在请求 CSS/JS 时会根据媒体查询判断是否阻塞渲染。

GPU 进程

负责图层的栅格化和合成,加速动画和 3D 渲染。

插件或扩展进程

封装第三方插件或扩展,出现崩溃不会影响浏览器其他部分。

浏览器进程 (UI、标签管理)

渲染进程 (每个页面独立)

网络进程 (下载资源)

GPU进程 (栅格化与合成)

插件/扩展进程

图层栅格化请求

资源请求

Browser

Renderer

Network

GPU

Plugin

内部包含 DOM、CSSOM、JS 引擎(V8)、布局与绘制等

渲染流水线

资源获取

  • 处理地址栏/点击/重定向,可能经过 Service Worker。
  • 网络进程负责 DNS、TLS、HTTP/2/3 连接复用与首包返回,并根据响应头推断可预加载/预连接资源。
  • 把高延迟的 I/O 与主线程隔离,利用连接池和多路复用降低首字节等待。
  • 更快的 TTFB/TTI,失败隔离(网络进程崩溃不拖垮渲染)。

合理使用 preconnect/dns-prefetch/preload,用 SW 做缓存回源与离线兜底。

HTML解析

  • 渲染进程中的 HTML 解析器边收边解字节流,并构建 DOM
  • 解析过程中遇到 CSS,浏览器会启动⼀个预解析器率先下载和解析 CSS。
  • 解析过程中遇到 JS 代码,则必须暂停⼀切⾏为,等待下载执⾏完后才能继续,预解析线程可以分担⼀点下载 JS 的任务。

同步 <script> 会阻塞解析,defer 在 DOM Ready 后执行,async 一到就执行。

样式计算

  • DOM × CSSOM → 计算样式(Recalc Style),剔除 display:none 节点,得到渲染树(Render/Frame Tree)
  • 把语义树(DOM)与样式规则转为可布局的盒模型视图;仅可见元素进入后续管线。
  • 减少无用节点参与后续昂贵阶段(布局/绘制)。

content-visibility:auto;/contain 把子树与外界隔离,降低样式与布局影响域。

布局

  • 为渲染树中的每个盒子计算几何信息(位置、尺寸、换行、分页/分栏、表格排版等)。
  • 遇到 position: fixed/absolute、多列与复杂 inline 排版会增加复杂度。
  • 像排版引擎一样给每个盒子定位,保障视觉与交互正确。
  • 得到可用于绘制的布局树与几何缓存,后续绘制可复用。

新增/删除节点、修改盒子尺寸/字体、读取布局信息(在有未结算写入时)、窗口 resize、滚动(特定情况下)。

分层

  • 创建图层树(独立合成层:新层叠上下文、变换/滤镜、video/canvaswill-change 等).
  • 生成绘制列表(背景、边框、文本、阴影、图片等)。
  • 把可复用/可独立合成的区域拆分到独立层,降低重绘与滚动成本。
  • 滚动与 transform/opacity 动画可脱离主线程,仅在合成器中更新。

少量使用 will-change/transform: translateZ(0) 以“合成器驱动”动画,过多会吃内存。

绘制

为每⼀层⽣成如何绘制的指令,渲染主线程的⼯作到此为⽌,剩余步骤交给其他线程完成。

分块

分块会将每⼀层分为多个⼩的区域,此过程会交给多个线程同时进⾏。

光栅化

  • 光栅化是将每个块变成位图,优先处理靠近视⼝的块。
  • 此过程会⽤到 GPU 加速。

合成

  • 合成线程计算出每个位图在屏幕上的位置,交给 GPU 进⾏最终呈现。
  • 合成线程根据输入事件/滚动/动画对各瓦片做矩阵变换并合成一帧提交给 GPU。
  • 并行化重度工作,把每帧的变换留给轻量的合成器完成。
  • 高帧率滚动与动画;减少因主线程繁忙导致的掉帧。

导航/资源获取

HTML 流式解析 → DOM

CSS 解析 → CSSOM

预解析并行请求 → CSS 解析

样式计算 & 渲染树

S 编译与执行 V8

布局

分层 & 绘制

分块 & 栅格化

合成与显示

回流

当需要重新计算盒子几何信息时触发的布局阶段(如内容变化、样式影响尺寸、读取布局信息导致同步刷新),都会发生回流现象。

优化对策

触发因素

回流触发 ↔ 优化对策

DOM 结构变更
新增/删除/移动/改文本/切 display

几何类样式变更
width/height/margin/padding/top/left…

读写交错 → 强制同步布局
offset*/client*/scroll*/GBCR

视口/环境变化
resize/旋转/缩放/滚动条

媒体/字体加载后度量变化
图片/视频无尺寸;Web 字体切换

用布局属性做动画
height/width/top/left/margin/padding

样式影响域过大
深层级选择器/全局主题切换

复杂布局/特殊元素
table auto/多列/复杂 inline/iframe

DocumentFragment/离线容器构建/一次性 innerHTML/批量插入

动画用 transform/opacity;contain 或 content-visibility;table-layout:fixed

分离读写;合并进 requestAnimationFrame;批处理

节流/防抖;只合成的滚动;合理创建合成层

为媒体设 width/height 或 aspect-ratio;font-display:swap;预加载

仅动画 transform/opacity;少量使用 will-change 并及时移除

组件化/作用域化样式;@container;contain 限定影响域

固定列宽;优先 Grid/Flex;拆分热点区域/虚拟列表

重绘

样式改变但不影响几何信息(如 colorbackgroundbox-shadow)时,跳过布局、重新绘制位图。重绘仅影响命中的绘制列表范围,成本低于回流。

优化策略

触发场景

常见场景 ↔ 应对措施

颜色/背景变化
color/background/border-color

阴影/描边/装饰
box-shadow/text-shadow/outline/text-decoration

背景资源切换
background-image/渐变

:hover/:active 等状态切换
仅修改视觉样式

visibility: hidden/visible 切换

滚动导致非合成层重绘
大面积背景/固定背景滚动

频繁更新 Canvas/SVG 填充/描边样式

主题/暗色模式/自定义属性
影响颜色类样式

优先使用只合成的动画
transform/opacity 替代颜色/阴影渐变

缩小重绘范围
隔离组件:contain: paint;
必要时单独合成层,慎用will-change

降低绘制复杂度
减少大半径模糊/多重阴影/叠层渐变

用叠加层淡入淡出
用半透明覆盖层做高亮,避免频繁改底层背景

滚动优化
让滚动相关装饰进入合成层;避免 background-attachment: fixed 大图

资源管理
预加载/缓存背景图;使用合适分辨率与格式

绘图管线分离
Canvas/SVG 复杂绘制放 OffscreenCanvas/Web Worker

主题切换分层
把易变色块独立容器/层,减少全页重绘

独立合成层

合理地使用独立合成层,可减少回流与重绘。

行为 / 建议

属性 / 特性

独立合成层
Compositing

必然合成
video/iframe/canvas
filter/backdrop-filter
mix-blend-mode
will-change: transform/opacity/filter/clip-path

多半合成
translateZ/preserve-3d
大型可滚动容器
isolation: isolate(结合合成需求)

动画时合成
transform 动画
opacity 动画
部分 clip-path/filter 动画

不会合成
color/background/border-color
box-shadow/text-shadow
background-image
visibility 切换

GPU 合成器处理
滚动/动画更流畅

谨慎“强制合层”
优先用 will-change(动画后移除)

合成器驱动动画
避免回流/重绘

仅重绘不合层
用覆盖层 + opacity/transform 做过渡

检查工具
DevTools Layers / Paint flashing

成本注意
过多图层占内存;大模糊/半透明叠加昂贵

常见误区

  • 读写交错:先写样式后立刻读 offsetHeight/scrollTop/getComputedStyle 会触发强制同步布局;解决:把写合并、把读合并,或放到 requestAnimationFrame
  • 大量DOM:大量节点让样式计算与布局指数级放大;使用 content-visibility:auto;、虚拟列表、分页加载。
  • 不必要的图层:过多 will-change 让 GPU 内存暴涨;应限量使用并在动画结束后移除。

性能优化

样式/布局层

  • Containmentcontain: layout style paint;content-visibility:auto; 隔离子树影响域。
  • 响应式策略:优先 @container 与现代布局(Grid/Flex),减少 JS 测量。
  • 避免抖动:首屏内联关键 CSS;字体使用 font-display: swap;图片提供尺寸/占位,降低 CLS。

动画/交互层

  • 只合成的动画:优先 transformopacity;必要时加 will-change
  • 帧内时序:动画更新放 rAF;非紧急工作放 requestIdleCallback 或切 Worker。
  • 输入响应:把重活分片(小任务 < 3~5ms),减少长任务。

JS/V8 层

  • 避免主线程阻塞:大计算用 Web Worker/OffscreenCanvas。
  • 减少同步布局读:读布局放一起,写样式放一起。
  • 模块化与按需执行type=module 的动态导入、路由级拆分;使用懒执行/延迟解析。

渲染/合成层

  • 合理分层:对滚动容器/动画元素创建合成层;避免半透明大区域叠加。
  • 图片/视频:使用现代格式(WebP/AVIF),合理 srcset/sizes,开启 decoding=asyncloading=lazy