aurora blog
  • JS

    • 基本汇总
    • Date时间
    • Array方法
    • String 方法
    • Object方法
    • RegExp正则
    • Es6 新特性等
    • Event-Loop
    • Http and Https
    • for in和for of区别
    • Web Worker
    • Promise && async
    • 堆内存 & 栈内存
    • JS设计模式探索
    • npm & yarn
    • Fetch和Axios的区别
    • 学习及面试问题整理
    • URL 输入到页面加载过程
    • 跨域&nginx本地项目代理
  • FE框架

    • react

      • 基本用法
      • react生命周期
      • hooks 16.8版本后
      • Route原理
      • Redux源码解析
      • React16 Fiber
      • React-VirtualDOM
      • React事件委托机制
      • React性能优化
      • 状态管理方案对比
      • React 18新特性
    • vue

      • vue 基本用法
      • vue 生命周期
      • VirtualDOM
      • vue 事件委托
      • vue 架构
      • vue 状态管理
      • 问题等
    • React-Native

      • React-Native 基本用法
    • 微前端

      • 遇到的问题
    • 鸿蒙 harmony

      • harmony 基础
  • 构建工具

    • webpack

      • Webpack配置详解
      • Webpack的使用
      • Babel-polyfill
      • webpack面试题
    • vite

      • vite配置详解
      • vite面试题
    • rollup

      • Rollup配置详解
      • rollup面试题
    • 构建工具对比
  • 性能优化

    • 性能优化策略
    • 缓存策略
    • 性能优化面试题
  • 浏览器

    • 浏览器渲染原理
    • 浏览器缓存机制
    • 浏览器面试题
  • 工程化

    • 代码规范
    • 工程化面试题
  • 前端安全

    • XSS 攻击与防护
    • CSRF 攻击与防护
    • 前端安全面试题
  • 移动端开发

    • 移动端适配
    • 移动端开发面试题
  • 前端监控

    • 错误监控
    • 性能监控
    • 前端监控面试题
  • Typescript

    • Typescript详解
  • Servers

    • Nodejs
    • Nginx
  • Git命令

    • git常用规范
  • 数据库

    • mongodb
    • mongodb
  • Other

    • Jenkins自动化部署

浏览器渲染原理

  • 浏览器架构
    • 多进程架构
    • 渲染进程组成
  • 渲染流程
    • 1. 构建 DOM 树
    • 2. 构建 CSSOM 树
    • 3. 构建渲染树(Render Tree)
    • 4. 布局(Layout/Reflow)
    • 5. 绘制(Paint)
    • 6. 合成(Composite)
  • 关键渲染路径优化
    • 阻塞渲染的资源
    • 优化策略
  • 重排和重绘
    • 重排(Reflow)
    • 重绘(Repaint)
    • 合成(Composite)
  • 渲染优化
    • 1. 减少重排重绘
    • 2. 使用合成层
    • 3. 优化选择器
    • 4. 避免强制同步布局
  • 浏览器缓存
    • 缓存位置
    • 缓存流程
  • 性能指标
    • 关键时间点
  • 最佳实践
    • 1. 优化关键渲染路径
    • 2. 减少重排重绘
    • 3. 合理使用合成层
    • 4. 优化资源加载

浏览器架构

多进程架构

主要进程:

  1. 浏览器主进程:界面显示、用户交互、子进程管理
  2. 渲染进程:页面渲染、JS 执行
  3. GPU 进程:3D 绘制、CSS 动画
  4. 网络进程:网络资源加载
  5. 插件进程:浏览器插件

渲染进程组成

线程:

  • 主线程:JS 执行、DOM 解析、样式计算、布局、绘制
  • 合成线程:图层合成
  • 光栅化线程:图层分块、光栅化
  • Worker 线程:Web Worker

渲染流程

1. 构建 DOM 树

HTML 解析:

HTML 字节流 → 字符流 → Token → 节点 → DOM 树

解析过程:

  1. 字节流转换为字符
  2. 词法分析生成 Token
  3. 语法分析构建节点
  4. 构建 DOM 树

阻塞情况:

  • JS 会阻塞 DOM 解析
  • CSS 不会阻塞 DOM 解析,但会阻塞渲染

2. 构建 CSSOM 树

CSS 解析:

CSS 字节流 → Token → 节点 → CSSOM 树

特点:

  • 从右到左匹配选择器
  • 解析会阻塞渲染

3. 构建渲染树(Render Tree)

过程:

  1. 遍历 DOM 树
  2. 找到对应的 CSS 规则
  3. 创建渲染对象(RenderObject)
  4. 构建渲染树

不包括:

  • display: none 的元素
  • <head> 中的元素
  • <script>、<meta> 等

4. 布局(Layout/Reflow)

计算位置和大小:

  • 计算每个元素的几何信息
  • 确定元素在页面中的位置

触发条件:

  • 添加或删除 DOM 元素
  • 改变元素位置、尺寸
  • 改变窗口大小
  • 改变字体大小

5. 绘制(Paint)

绘制过程:

  • 遍历渲染树
  • 调用渲染对象的 paint 方法
  • 绘制到图层

绘制顺序:

  1. 背景色
  2. 背景图片
  3. 边框
  4. 子元素
  5. 轮廓

6. 合成(Composite)

图层合成:

  • 将多个图层合并
  • 输出到屏幕

合成层:

  • transform、opacity 会创建合成层
  • 合成层由 GPU 处理,性能更好

关键渲染路径优化

阻塞渲染的资源

CSS:

  • 阻塞渲染
  • 应该放在 <head> 中
  • 关键 CSS 可以内联

JavaScript:

  • 阻塞 DOM 解析
  • 应该放在 </body> 前
  • 或使用 async、defer
<!-- 异步加载,不阻塞解析 -->
<script async src="script.js"></script>

<!-- 延迟执行,不阻塞解析 -->
<script defer src="script.js"></script>

优化策略

1. 减少关键资源数量

  • 内联关键 CSS
  • 延迟非关键 CSS
  • 异步加载非关键 JS

2. 减少关键资源大小

  • 压缩 CSS/JS
  • 移除未使用的 CSS
  • Tree Shaking

3. 缩短关键渲染路径长度

  • 减少 CSS 层级
  • 优化选择器
  • 减少 DOM 层级

重排和重绘

重排(Reflow)

触发条件:

  • 改变窗口大小
  • 改变字体大小
  • 添加/删除 DOM 元素
  • 改变元素位置、尺寸
  • 读取布局属性(offsetTop、scrollTop 等)

优化:

// ❌ 不好:多次重排
element.style.width = '100px';
element.style.height = '100px';
element.style.margin = '10px';

// ✅ 好:一次重排
element.style.cssText = 'width: 100px; height: 100px; margin: 10px;';

// ✅ 更好:使用 class
element.className = 'new-style';

重绘(Repaint)

触发条件:

  • 改变颜色
  • 改变背景
  • 改变边框样式
  • 改变 visibility

优化:

  • 使用 transform 和 opacity(触发合成层)
  • 批量修改样式
  • 使用 will-change 提示浏览器

合成(Composite)

合成层:

  • 使用 transform、opacity、will-change
  • 由 GPU 处理,性能最好
  • 不会触发重排和重绘
/* ✅ 创建合成层,GPU 加速 */
.element {
  transform: translateX(100px);
  opacity: 0.5;
  will-change: transform;
}

渲染优化

1. 减少重排重绘

方法:

  • 使用 transform 和 opacity
  • 批量 DOM 操作
  • 使用 DocumentFragment
  • 避免频繁读取布局属性

2. 使用合成层

创建合成层:

  • transform: translateZ(0)
  • opacity < 1
  • will-change
  • position: fixed

注意:

  • 合成层过多会消耗内存
  • 合理使用,不要过度

3. 优化选择器

选择器性能:

/* ✅ 快:ID 选择器 */
#header { }

/* ✅ 快:类选择器 */
.header { }

/* ⚠️ 慢:属性选择器 */
[data-id="header"] { }

/* ❌ 很慢:伪类选择器 */
:not(.header) { }

4. 避免强制同步布局

问题代码:

// ❌ 强制同步布局
for (let i = 0; i < items.length; i++) {
  items[i].style.width = items[i].offsetWidth + 10 + 'px';
}

优化:

// ✅ 先读取,再写入
let widths = [];
for (let i = 0; i < items.length; i++) {
  widths[i] = items[i].offsetWidth;
}
for (let i = 0; i < items.length; i++) {
  items[i].style.width = widths[i] + 10 + 'px';
}

浏览器缓存

缓存位置

1. Service Worker

  • 可编程缓存
  • 离线可用

2. Memory Cache

  • 内存缓存
  • 关闭标签页清除

3. Disk Cache

  • 磁盘缓存
  • 持久化存储

4. Push Cache

  • HTTP/2 推送缓存
  • 会话级别

缓存流程

1. 检查 Service Worker
2. 检查 Memory Cache
3. 检查 Disk Cache
4. 发起网络请求
5. 存入缓存

性能指标

关键时间点

Navigation Timing:

  • navigationStart:开始导航
  • domLoading:开始解析 DOM
  • domInteractive:DOM 解析完成
  • domContentLoaded:DOMContentLoaded 事件
  • domComplete:DOM 和资源加载完成
  • loadEventEnd:load 事件结束

计算指标:

const timing = performance.timing;

// DNS 查询时间
const dnsTime = timing.domainLookupEnd - timing.domainLookupStart;

// TCP 连接时间
const tcpTime = timing.connectEnd - timing.connectStart;

// 请求响应时间
const requestTime = timing.responseEnd - timing.requestStart;

// DOM 解析时间
const domParseTime = timing.domInteractive - timing.responseEnd;

// 页面加载时间
const loadTime = timing.loadEventEnd - timing.navigationStart;

最佳实践

1. 优化关键渲染路径

  • 内联关键 CSS
  • 异步加载非关键资源
  • 减少 DOM 层级
  • 优化选择器

2. 减少重排重绘

  • 使用 transform 和 opacity
  • 批量 DOM 操作
  • 避免强制同步布局

3. 合理使用合成层

  • 动画使用合成层
  • 避免过度使用
  • 注意内存占用

4. 优化资源加载

  • 使用 CDN
  • 启用压缩
  • 使用 HTTP/2
  • 预加载关键资源
最近更新:: 2025/11/20 14:50
Contributors: liyulai
Next
浏览器缓存机制