浏览器原理✅
浏览器架构及主要组成部分?
答案
参考 浏览器的工作方式
浏览器核心组成部件如下图

- 界面:包括地址栏、后退/前进按钮、书签菜单等。浏览器界面的每个部分,但显示请求网页的窗口除外。
- 浏览器引擎:在界面和渲染引擎之间协调操作。
- 渲染引擎:负责显示请求的内容。例如,如果请求的内容是 HTML,则呈现引擎会解析 HTML 和 CSS,并在屏幕上显示解析的内容。
- 网络:对于 HTTP 请求等网络调用,在平台无关接口后面为不同平台使用不同的实现。
- 界面后端:用于绘制组合框和窗口等基本 widget。此后端公开的接口并非平台专用。在底层,它使用操作系统界面方法。
- JavaScript 解释器:用于解析和执行 JavaScript 代码。
- 数据存储:这是持久层。浏览器可能需要在本地保存各种数据,例如 Cookie。浏览器还支持 localStorage、IndexedDB、WebSQL 和 FileSystem 等存储机制。 浏览器的主要组成部分是什么
整个进程模型参考 https://www.chromium.org/developers/design-documents/multi-process-architecture/

- Borwser Process 主进程 管理渲染进程和其他进程
- Main Thread 主线程,管理渲染进程
- IO Thread IO线程,处理网络请求
- Renderer Process 渲染进程,负责渲染页面
- Main Thread 渲染进程的主线程,负责解析HTML、CSS和JavaScript
- Render Thread 工作线程,处理后台任务等
这是一个概念上的示意图,实际上 chrome 还包含插件进程、GPU 进程等其他进程,此外也可通过配置等控制进程执行模式。
延伸阅读
- how blink work chromium 团队对整个 blink 概览
- inside browser
- How Chromium Displays Web Pages
常见浏览器内核及区别?
答案
| 内核 | 概述 |
|---|---|
| Blink | 由Google和Opera Software共同开发,基于WebKit内核,是Chrome浏览器和Opera浏览器的渲染引擎。 |
| WebKit | 由苹果公司开发,为Safari浏览器所用。Kit内核在HTML、CSS和JavaScript处理方面都表现出色,支持的CSS特性较多。 |
| Gecko | 由Mozilla开发,主要用于Firefox浏览器。 |
| Trident | 由Microsoft开发,主要用于Internet Explorer浏览器,也是Windows系统自带的默认浏览器内核。从 2018 微软切换到基于 chromium 的 Blink 内核的 Edge 浏览器后,Trident 内核逐渐被淘汰。 |
输入 url 到页面渲染全过程?
答案
- Loading(加载阶段) 细节参考 network
- URL 解析 , 浏览器解析 URL,提取协议、域名、路径等信息。
- Cache Check ,检查缓存,判断资源是否新鲜,决定是否重新请求。
- DNS, 进行 DNS 查询,解析出服务器 IP 地址。
- TCP, 建立 TCP 连接(三次握手)。
- TLS, 如果是 HTTPS 协议,进行 TLS 握手,建立安全连接。
- HTTP, 发送 HTTP 请求,获取资源。
- Parsing(HTML 和资源解析)
- DOM Tree 解析 HTML 文档,构建 DOM 树。注意 DOM 树的解析是流式的,浏览器会在解析过程中逐步构建 DOM 树,而不是等到整个文档加载完成再解析,这里的 Tokenizer 在单独线程进行,详情参考 html 文档解析调度
- JS Execution 解析并执行 JavaScript,可能会修改 DOM 树或触发其他资源加载。
- CSSOM Tree 解析 CSS,构建 CSSOM 树
- Style(样式计算) 详见 style
- CSSOM 将样式表解析为 CSSOM(CSS 对象模型)。
- RenderObject Tree 基于 DOM 节点和 CSSOM 构建渲染对象树。
- Layout(布局计算) 详见 layout
- Layout 基于 DOMTree 和 CSSOM 计算每个渲染对象的实际位置与尺寸,基于 CSS 视觉格式化模型会拆解不同的渲染元素,比如
LayoutBlock、LayoutInline、LayoutText等。 - LayoutTree 生成整个文档树对应的布局树。新版架构叫做 NGLayout(next generation layout),
- Layout 基于 DOMTree 和 CSSOM 计算每个渲染对象的实际位置与尺寸,基于 CSS 视觉格式化模型会拆解不同的渲染元素,比如
- Paint(绘制阶段) 将样式化的内容转化为图层绘制命令与位图,完成从逻辑表示到图像数据的过渡。阅读 paint 了解细节
- GraphicsLayer Tree 根据是否具有合成需求(如
transform、opacity、will-change等)从 LayoutTree 构建 GraphicsLayer Tree,每个 GraphicsLayer 可单独绘制和合成。 - Paint Setup 为每个图层生成绘制命令(Display List,如 SkPicture),这些命令是可复用的中间格式。通过 GPU 命令缓冲区 共享给 GPU
- GraphicsLayer Tree 根据是否具有合成需求(如
- Compositing(合成阶段) 这阶段工作在 compositor 线程,Compsiting 阶段会使用 Slimming Paint 技术来优化合成性能,减少不必要的重绘和重排。你可以通过 layer-borders 查看 chrome 如何切片和分层
- Compositing Setup Compositor 线程根据 GraphicsLayer Tree 的结构,生成组合属性树(Compositor Property Tree),用于描述每个图层的变换、透明度等属性。你可以通过 Chrome Layers 工具查看合成树。
- Raster 对每个图层进行光栅化,将 Display List 转换为位图数据。光栅化可以在 CPU 或 GPU 上执行,取决于具体实现和配置。生成管线命令光栅化底层使用 skia
- Composite 将所有图层位图合成为最终帧, 详见 Compositing
- Presentation 合成帧经由 GPU 管线提交至操作系统显示系统(如 Windows DWM 或 macOS Quartz),完成屏幕更新。
- Display(显示阶段) 工作在 gpu 进程和显示器,将合成的图像数据发送到显示设备(如屏幕、投影仪等),完成最终的视觉呈现。
- Display Output GPU 负责将合成的图像数据发送到显示设备进行渲染
上面是首次加载流程,页面会由于用户滚动或者其他事件触发更新,浏览器会尽可能实现增量更新。这里需要重点注意 reflow 和 repaint 的区别,reflow 相当于从 layout 管道重新计算布局,而 repaint 则只触发 paint 及后续环节。
此外这里是首帧的刷新,而 blink 引擎内部会基于 vsync 机制来协调渲染帧的更新与显示刷新,确保视觉效果的流畅性。参考 Life of a frame 理解每帧的绘制
延伸阅读
- Life of a Pixel blink 渲染管线的工作原理
- Blink Rendering 更加通俗的讲解 blink 渲染管线的工作原理
- RenderingNG chrome 新的渲染管线
- The Rendering Critical Path
- render pipeline
- life of frame 图示说明渲染帧的执行逻辑
- Rendering Architecture Diagrams 更细节的渲染图,详细说明了涉及的对象
- CompositeAfterPaint 讲解 compositeAfterPaint 的工作原理
- Rendering Core 一系列资料了解 blink 选的个模块
- layoutNg 新一代 layout 系统说明
- skia chrome 底层使用 skia 作为渲染引擎,skia 是一个开源的 2D 图形库,提供了丰富的图形绘制 API。
- Compositor Pipeline 详细讲解组合的渲染管道
- Audio / Video Playback chromium 讲解视频的渲染管线
- MDN MDN 浏览器渲染管线概述
什么是合成阶段(Compositing)?
答案
通过合成阶段浏览器会将渲染树分解为多个图层(Layer),每个图层可以独立绘制,从而尽可能降低重绘和重排的开销。合成阶段的主要任务包括
- 图层划分:将渲染树中的节点划分为多个图层。每个图层可以独立绘制和合成,减少不必要的重绘和重排。这时候会生成 compositor property tree, 比如 transform、opacity、clip-path 、video 等属性会被划分到独立的图层。
- 光栅化:将每个图层的绘制命令转换为位图数据。光栅化可以在 CPU 或 GPU 上执行
- 合成:将所有图层的位图数据合成为最终的渲染帧。合成可以在 GPU 上执行,利用 GPU 的并行处理能力提高性能。
延伸阅读
- Compositing in Blink 详细讲解合成阶段
- GPU Accelerated Compositing in Chrome 讲解 GPU 加速合成的逻辑
- How cc Works chromium 源码说明 Chrome Compositor(cc) 的工作原理
什么是光栅化(raster),软件光栅化和 GPU 光栅化的区别?
答案
光栅化是将渲染指令翻译为像素点的过程,主要分为软件光栅化和 GPU 光栅化两种方式。
- 软件光栅化:通过 CPU 进行光栅化处理, SKIA 会将渲染指令转换为像素数据,然后把调用指令把像素数组传递给 GPU 执行。
- GPU 光栅化:渲染进程会直接把命令写入一个 GPU 命令缓冲区,GPU 直接执行光栅化操作。GPU 光栅化通常比软件光栅化更高效,因为它可以利用 GPU 的并行处理能力。但是在处理文本和复杂矢量图形时,软件光栅化可能更精确。
延伸阅读
DOM/CSSOM/渲染树构建?
答案
核心概念
DOM(文档对象模型)和 CSSOM(CSS对象模型)是浏览器渲染页面的基础数据结构。浏览器会将 HTML 解析为 DOM 树,将 CSS 解析为 CSSOM 树,然后结合两者生成渲染树(Render Tree),用于后续的布局和绘制。
- html 解析可以参考 html parser 规范
- cssom 可以参考 cssom
详细解释
- 解析 HTML 生成 DOM 树:浏览器自上而下读取 HTML,遇到标签就创建节点,嵌套结构形成父子关系,属性和文本也会作为节点挂载。
- 解析 CSS 生成 CSSOM 树:CSS 解析器将样式表转为规则对象,形成树状结构,便于后续样式计算。
- 构建渲染树:DOM 树与 CSSOM 树结合,过滤掉 display: none 的节点,仅保留可见元素,生成渲染树。每个渲染树节点都包含 DOM 元素及其最终计算样式。
- 渲染树用于布局(Layout)和绘制(Paint)阶段,决定元素的几何信息和视觉表现。
CSS选择器从右往左解析原理
浏览器在匹配 CSS 选择器时,从选择器最右侧(即目标元素)开始,逐级向左查找父节点是否匹配,直到根节点或选择器左端。这样可以快速排除不匹配的分支,提升性能。例如 .a .b .c,会先查找 .c,再判断其父节点是否有 .b,依次类推。
代码示例
<div class="a">
<div class="b">
<span class="c">text</span>
</div>
</div>
.a .b .c { color: red; }
浏览器会先定位 .c,再判断其父级是否有 .b,再向上查找 .a,而不是从 .a 开始遍历所有后代。
常见误区与开发建议
- 误区:以为 CSS 选择器是从左往右解析,导致过度嵌套选择器以期望优化性能,实则适得其反。
- 建议:减少层级选择器和通配符(*)的使用,优先使用类选择器,提升样式匹配效率。
合理优化选择器结构,能显著提升页面渲染性能,尤其在大型 DOM 树下效果明显。
延伸阅读
事件循环原理、宏任务与微任务?
答案
HTML 规范 event loops 章节。定义的 事件循环处理模型 如下
-
任务类型
- 任务(task) 规范中没有宏任务这个概念,对于常说的宏任务(macro task) 对应规范的任务(task) 。任务会分为很多类型,通过 Source 区分。常见的任务包括
- 用户交互任务(The user interaction task source):如用户交互事件(点击、输入等)。
- 渲染任务(Rendering task):浏览器渲染相关的任务。
- 网络任务(Networking task):如 XMLHttpRequest、fetch、图片加载等。
- 定时器任务(Timer task):如 setTimeout、setInterval 等。
- 微任务(microtask) 独立于任务是一个单独的队列,会在每次宏任务处理完毕后立即执行,按照先进先出(FIFO)顺序执行。典型的微任务如下
- Promise 微任务,由 V8 控制
- MutationObserver 微任务,blink 控制
- queueMicrotask 微任务, 浏览器提供的 API,相比采用 Promise, MutationObserver 等方式更语义化, 阅读 解释 queueMicrotask 理解设计初衷
- 特殊任务 此外还有一些特殊的任务,也在 Task 的范畴这里单独列出
- requestIdleCallback 提供浏览器闲时调度能力
- requestAnimationFrame 提供在渲染绘制前执行的能力,多用于动画
- 任务(task) 规范中没有宏任务这个概念,对于常说的宏任务(macro task) 对应规范的任务(task) 。任务会分为很多类型,通过 Source 区分。常见的任务包括
-
任务执行顺序
- 对于任务会按照推入顺序和优先级执行,具体策略由浏览器决定,一般的规则如下,用户事件优先级最高
- 每个任务执行完毕,会检查微任务队列是否为空,如果有值,按照微任务的推入顺序执行所有微任务,直到微任务队列清空。注意由于微任务存在清空操作,要避免大量微任务导致 IO 饥饿,此时可以通过 requestIdleCallback 避免此问题
-
事件循环 基于上述的任务处理流程存在三种类型的事件循环
- 窗口事件循环(window event loop) 也就是我们常说的渲染进程主线程的事件循环,处理用户交互、渲染等任务。
- 工作线程事件循环(worker event loop) 处理 Web Worker 中的任务,独立于主线程。
- worklet 线程(worklet event loop) 处理 Worklet 中的任务,独立于主线程,适用于音频处理、绘图等场景,是一个轻量级的 worker 线程
以上就是规范定义的核心逻辑,但是浏览器的实现会更复杂一些,以 chromium 为例,参考 blink 任务调度说明
- 任务类型 浏览器会将任务作进一步细分,可以参考 源码 task_typs 查看细分类型
- 任务调度 为了尽可能能避免阻塞渲染,浏览器会优化任务的调度核心设计包括
- 任务优先级 在 task_traits 定义了不同的任务类型由高到低
- USER_BLOCKING 直接导致页面重新渲染的用户行为,例如滚动,窗口尺寸变化等
- USER_VISIBLE 用户可见的任务,例如点击按钮,下载文件,加载图片等
- LOWEST 最低优先级的任务,例如日志上报,预加载等
- 调度策略 浏览器会根据任务状态和优先级运行环境提供不同调度策略, 对于不同类型任务是否存在如下策略可以参考 task type 表格
- 暂停(Pausing) 例如
alert,print,debugger可以暂定 js 执行(这里是直接阻塞主线程即使是同步任务也能暂定) - 延迟(Deferring) 基于优先级实现延迟调度,典型的包括
requestidlecallback的闲时判断,触发了多个任务的时候按照优先级处理等 - 冻结(Freezing) 在页面处于后台的场景满足特定规则会出现页面冻结,避免不必要的资源消耗,例如安卓设备在后台 5 分钟会触发此逻辑。
- 限流(Throttling) 在后台对定时器等事件降低触发频率,避免不必要的资源消耗,例如
setTimeout、setInterval在后台情况满足限流条件会延迟为 1 分钟触发一次,即使你设置了更短的时间间隔,详见 throttling in chrome
- 暂停(Pausing) 例如
- 任务优先级 在 task_traits 定义了不同的任务类型由高到低
- 闲时调度(Idle Scheduling) 参考 blink 闲时调度 说明, 渲染进程在每帧 commit 给 compositor 线程后和下一帧 willBeginFrame 前,会有一段空闲时间,此时可以执行例如
requestIdleCallback的任务。js 定时器调度也被优化到了这个阶段,可以参考 调度 js 定时器执行 了解细节
延伸阅读
- The Blink Scheduler PPT 讲解 blink 调度策略,虽然时间是 2014 年,但是核心理念值得参考, 对应 视频
- blink 调度设计文档 详细讲解 blink 调度模式
- Scheduler 2.0 设计文档
- Blink Scheduler 重构设计文档
- Tasks, Microtasks, Queues and Schedules 详细讲解浏览器事件循环
- schedule docs chromium 调度文档汇总,有很多有用的信息
- Event Loop 運行機制解析 - 瀏覽器篇 浏览器详解
- event_loop chromium 源码 event loop 相关说明
- 事件分发图 此图可以理解浏览器每帧绘制的流程和事件的派发策略
- 调度工作全景图 显示了浏览器调度工作全景
- 从Chrome源码看事件循环 提供了源码级别的分析
- scheduler link blink 调度相关文档汇总
重排和和重绘及优化?
答案
- 重排(reflow) 发生在浏览器重新计算网页的某些部分的位置和几何形状时(例如在交互式站点更新后)。这通常会紧接着重绘(repaint),即浏览器重新绘制网页以显示更新后的视觉效果。
- 重绘(repaint) 重绘在浏览器重新绘制网页以显示由 UI 更改引起的视觉更新时发生,例如在交互式站点上进行更新后。这通常是在重排之后发生的,重排是浏览器重新计算网页的某些部分的位置和几何形状。
重排和重绘是导致浏览器性能下降的主要原因之一,这里重点关注重排,因为它比重绘更耗费资源。
参考 What forces layout / reflow 常见触发重排的操作如下
- 直接修改元素的几何属性,如
width、height、top、left、margin、padding、border-width等。 - 插入、删除 DOM 节点,或更改节点结构(如
appendChild、removeChild、insertBefore等)。 - 读取会触发布局的属性和方法,如
offsetWidth、offsetHeight、offsetTop、offsetLeft、clientWidth、clientHeight、getBoundingClientRect()、getClientRects()。 - 访问滚动相关属性和方法,如
scrollTop、scrollLeft、scrollWidth、scrollHeight、scrollTo()、scrollBy()、scrollIntoView()。 - 设置或获取元素的
focus()、select()、innerText。 - 读取
window.getComputedStyle(),尤其是访问返回对象的属性时。 - 修改表单元素的选区(如
input.select()、textarea.select())。 - 读取或设置 SVG 某些属性和方法(如
getBBox()、getComputedTextLength())。 - Canvas2D API 某些操作(如
fillText()、strokeText()、设置direction、filter)。 - 读取窗口尺寸相关属性,如
window.innerWidth、window.innerHeight、window.scrollX、window.scrollY(部分浏览器实现)。
在错误的触发重排的场景下,通过如下方式优化性能
- 批量修改 DOM:将多次 DOM 操作合并为一次操作,减少重排次数。例如,使用
DocumentFragment或cloneNode批量插入节点。 - 使用 CSS 类:通过添加或删除 CSS 类来批量修改样式,而不是逐个修改样式属性。这样可以减少重排次数。
- 使用
requestAnimationFrame:将需要重排的操作放在requestAnimationFrame回调中执行,这样可以确保在浏览器下一次重绘之前进行布局计算。 - 避免频繁读取布局属性:如果需要多次读取布局属性,可以先将其存储在变量中,避免多次触发重排。例如,使用
let rect = element.getBoundingClientRect()存储布局信息,然后在需要时使用该变量。 - 使用
will-change:对于需要频繁更新的元素,可以使用will-changeCSS 属性来提示浏览器提前进行优化,减少重排的开销。 - 使用 CSS 动画:尽量使用 CSS 动画而不是 JavaScript 动画,CSS 动画通常会触发 GPU 加速,减少重排的开销。
对于 css 详见 CSSTriggers 讲解哪些 CSS 属性会触发重排和重绘。
延伸阅读
- How repaint works chromium 讲解重绘的工作流程
- Understanding Reflow and Repaint in the browser 详细讲解 repaint 和 reflow 概念
- 理解 Web 的重排和重绘 大漠详细讲解重排和重绘
浏览器渲染进程内存结构是怎样的?
答案
延伸阅读
- Blink GC 讲解 Blink 的垃圾回收机制
浏览器缓存中 Memory Cache 和 Disk Cache, 有啥区别?
答案
- Memory Cache(内存缓存):资源直接存储在内存中,访问速度极快(纳秒级),但容量有限,通常在刷新或关闭页面后失效。适合当前会话内频繁访问的资源。
- Disk Cache(磁盘缓存):资源存储在硬盘上,访问速度比内存慢(毫秒级),但容量大,关闭浏览器后依然保留。适合长期存储和较大体积的资源。
核心概念
Memory Cache(内存缓存)和 Disk Cache(磁盘缓存)都是浏览器用来提升资源加载速度的缓存机制,区别在于存储介质和访问速度。
详细解释
- Memory Cache:资源被直接缓存在内存中,访问速度极快(纳秒级),但容量有限,重启浏览器或刷新页面后通常会失效。适合短期、频繁访问的资源。
- Disk Cache:资源被缓存在本地硬盘,访问速度比内存慢(毫秒级),但容量大,关闭浏览器后依然保留。适合长期存储、较大体积的资源。
