浏览器工作原理及其实践
目前的业务是通过原生应用通过 native 的 webview 来显示网页,所以需要了解下浏览器的原理。本文总结自极客时间的浏览器工作原理课程,旨在梳理浏览器底层机制,为前端开发和性能优化提供理论基础。
浏览器架构
多进程架构
现代浏览器采用多进程架构,以提高稳定性、安全性和性能。以 Chrome 浏览器为例,主要包含以下进程:
浏览器进程(Browser Process)
浏览器的主进程,负责:
- 用户界面管理:地址栏、书签栏、前进后退按钮等 UI 元素
- 标签页管理:创建、关闭、切换标签页
- 安全性:处理安全策略、证书验证
- 网络请求协调:协调各个渲染进程的网络请求
- 文件系统访问:管理下载、文件访问权限
渲染进程(Renderer Process)
每个标签页通常对应一个独立的渲染进程,负责:
- HTML 解析:将 HTML 文档解析成 DOM 树
- CSS 解析:解析样式表,生成 CSSOM
- JavaScript 执行:运行页面中的 JavaScript 代码
- 页面渲染:将内容绘制到屏幕上
- 事件处理:处理用户交互事件
进程隔离的优势: - 一个标签页崩溃不会影响其他标签页 - 不同标签页之间的 JavaScript 无法直接访问 - 提高了浏览器的整体稳定性
GPU 进程(GPU Process)
专门处理图形渲染任务:
- 硬件加速:利用 GPU 加速页面绘制和动画
- 3D 图形处理:WebGL、CSS 3D 变换等
- 视频解码:硬件加速的视频播放
网络进程(Network Process)
处理所有网络相关任务:
- HTTP/HTTPS 请求:发送和接收网络请求
- DNS 解析:域名解析
- TLS/SSL 加密:处理 HTTPS 加密通信
- 缓存管理:管理 HTTP 缓存
进程间通信
浏览器进程和渲染进程之间通过 IPC(Inter-Process Communication) 进行通信:
- 渲染进程通过 IPC 请求资源
- 浏览器进程通过 IPC 发送用户输入事件
- 渲染进程通过 IPC 通知浏览器进程页面状态变化
渲染流程
浏览器将网页从 HTML 转换为可视化页面的过程称为渲染流程,主要包括以下步骤:
1. 构建 DOM 树
HTML 解析过程:
- 字节流 → 字符流:将网络接收的字节流转换为字符流
- 字符流 → Token:HTML 解析器将字符流解析成 Token
- Token → 节点:将 Token 转换为 DOM 节点
- 节点 → DOM 树:将节点构建成 DOM 树
解析特点: - 边下载边解析,不需要等待整个 HTML 下载完成 - 遇到 <script> 标签会阻塞解析,等待脚本执行完成 - 遇到 <link> 和 <style> 标签会并行下载 CSS
2. 样式计算
CSS 解析过程:
- CSS 文本 → CSSOM:将 CSS 文本解析成 CSSOM(CSS Object Model)树
- 样式规则匹配:将 CSS 规则与 DOM 节点匹配
- 计算最终样式:处理继承、层叠、优先级,计算每个节点的最终样式
样式计算规则: - 继承:某些 CSS 属性会从父元素继承 - 层叠:多个样式规则可能应用到同一个元素 - 优先级:!important > 内联样式 > ID 选择器 > 类选择器 > 标签选择器
3. 布局(Layout)
布局阶段计算每个元素在页面中的位置和大小:
布局流程:
- 创建布局树:遍历 DOM 树,创建只包含可见元素的布局树
- 排除
display: none的元素 -
排除
head、script等不可见元素 -
计算布局:计算每个节点的几何信息
- 位置(x, y 坐标)
- 大小(width, height)
-
边距、内边距、边框
-
布局更新:当 DOM 或样式发生变化时,触发重新布局(reflow)
布局性能优化: - 避免频繁修改 DOM - 使用 transform 和 opacity 代替修改布局属性 - 批量修改 DOM,减少布局次数
4. 分层(Layer)
为了优化渲染性能,浏览器会将页面分成多个图层:
分层策略: - 拥有 3D 变换的元素(transform: translateZ(0)) - 使用 will-change 属性的元素 - 视频、Canvas 等元素 - 有滚动容器的元素
图层优势: - 独立合成,互不影响 - 可以利用 GPU 加速 - 只重绘变化的图层
5. 绘制(Paint)
绘制阶段将每个图层的绘制指令记录到绘制列表中:
绘制内容: - 背景色、背景图片 - 边框 - 文字 - 阴影等视觉效果
绘制优化: - 减少绘制区域 - 使用 CSS 动画代替 JavaScript 动画 - 避免复杂的 CSS 效果
6. 合成(Compositing)
合成阶段将各个图层合成为最终的页面图像:
合成流程: 1. 主线程将绘制列表提交给合成线程 2. 合成线程将图层分块(tiles) 3. 光栅化线程将分块转换为位图 4. 合成线程将位图合成为最终图像 5. 显示到屏幕上
合成优势: - 合成操作在合成线程完成,不阻塞主线程 - 可以利用 GPU 加速 - 只更新变化的图层
JavaScript 引擎
V8 引擎架构
Chrome 使用的 V8 引擎是高性能的 JavaScript 执行引擎:
主要组件
- 解析器(Parser)
- 将 JavaScript 代码解析成抽象语法树(AST)
-
进行词法分析和语法分析
-
解释器(Ignition)
- 将 AST 转换为字节码
-
执行字节码
-
编译器(TurboFan)
- 将热点代码(hot code)编译成机器码
- 优化代码执行效率
执行流程
JIT(Just-In-Time)编译: - 监控代码执行频率 - 将频繁执行的代码编译成机器码 - 提高执行效率
内存管理
堆内存结构
V8 将堆内存分为几个区域:
- 新生代(New Space):存放新创建的对象
- 老生代(Old Space):存放长期存活的对象
- 大对象空间(Large Object Space):存放大对象
- 代码空间(Code Space):存放编译后的代码
垃圾回收
新生代垃圾回收: - 使用 Scavenge 算法 - 将新生代分为两个区域:From 和 To - 将存活对象复制到 To 区域 - 清空 From 区域,交换 From 和 To
老生代垃圾回收: - 使用标记-清除(Mark-Sweep)算法 - 标记存活对象 - 清除未标记的对象 - 使用标记-整理(Mark-Compact)算法整理内存碎片
增量标记: - 将标记过程分成多个小步骤 - 与 JavaScript 执行交替进行 - 减少长时间停顿
浏览器安全机制
同源策略(Same-Origin Policy)
同源策略限制不同源的网页之间的交互:
同源定义: - 协议相同(http/https) - 域名相同 - 端口相同
限制内容: - Cookie、LocalStorage 等存储数据 - DOM 访问 - AJAX 请求
跨域解决方案: - CORS(Cross-Origin Resource Sharing) - JSONP - 代理服务器 - postMessage
沙箱机制(Sandboxing)
渲染进程运行在沙箱环境中:
沙箱限制: - 无法直接访问文件系统 - 无法直接访问网络 - 无法直接访问操作系统 API
安全优势: - 即使渲染进程被攻击,也无法影响系统 - 恶意代码被限制在沙箱内 - 提高了整体安全性
HTTPS 安全传输
HTTPS 工作原理:
- 证书验证:浏览器验证服务器证书
- 密钥交换:使用非对称加密交换对称加密密钥
- 加密通信:使用对称加密进行数据传输
安全特性: - 数据加密传输 - 防止中间人攻击 - 保证数据完整性
性能优化实践
渲染性能优化
- 减少重排和重绘
- 使用
transform和opacity代替修改布局属性 - 批量修改 DOM
-
使用
documentFragment减少 DOM 操作 -
优化 JavaScript 执行
- 避免长时间运行的 JavaScript
- 使用
requestIdleCallback执行非关键任务 -
代码分割,按需加载
-
优化资源加载
- 使用 CDN 加速资源加载
- 压缩资源文件
- 使用 HTTP/2 多路复用
内存优化
- 避免内存泄漏
- 及时清理事件监听器
- 避免循环引用
-
使用 WeakMap 和 WeakSet
-
优化对象创建
- 复用对象,避免频繁创建
- 使用对象池
- 避免创建大对象
总结
理解浏览器工作原理对于前端开发至关重要:
- 多进程架构提供了稳定性和安全性
- 渲染流程决定了页面显示效果和性能
- JavaScript 引擎的执行机制影响代码性能
- 安全机制保护用户数据和系统安全
掌握这些原理,可以帮助我们: - 编写更高效的代码 - 优化页面性能 - 解决复杂的浏览器兼容性问题 - 提升用户体验
参考
- 极客时间 - 浏览器工作原理与实践
- Chrome DevTools Performance 面板
- V8 引擎官方文档