以下内容按照思维导图的结构依次展开,分为六大部分:网络层、压缩、缓存、代码拆分、资源加载优化、预渲染 & 预加载,以及浏览器渲染原理。
1. 网络层
-
HTTP 版本迭代
- HTTP/1.0 → HTTP/1.1:持久连接、管线化(Pipeline),更高效的连接复用
- HTTP/2:多路复用(Multiplexing)、首部压缩(HPACK)、Server Push
- HTTP/3:基于 QUIC(UDP + 多路复用 + 0-RTT),更低时延、更好丢包恢复
-
协议栈对比
- OSI 七层模型:应用 / 表示 / 会话 / 传输 / 网络 / 数据链路 / 物理
- TCP/IP 四层模型:应用 / 传输 / 网络 / 数据链路
- HTTP 属于应用层协议,下面依次依赖 TCP、IP 及以太网等链路层
2. 资源压缩
-
构建时压缩(Compression Plugin)
- JS:TerserPlugin(去除死代码、压缩变量、内联常量)
- CSS:css-minimizer-webpack-plugin(合并、压缩 CSS 规则)
- 图片:现代格式(WebP/AVIF)、imageOptim 等工具进行无损/有损优化
-
部署时压缩
- Gzip:最广泛支持,压缩率中等
- Brotli:Google 推出,压缩率更高,但浏览器兼容略低
-
Tree Shaking(摇树优化)
- 基于 ES Module 静态分析,去除未引用的导出,减小打包体积
3. 缓存
-
文件名 & 内容哈希
- 使用
[filename].[contenthash].js形式,内容变更时哈希更新,便于缓存失效管理 - 常见哈希算法:Spark MD5、CRC32 等
- 使用
-
HTTP 缓存策略
- 强缓存(Cache-Control / Expires):浏览器直接使用本地缓存,无条件请求
- 协商缓存(Last-Modified / ETag):浏览器带上请求头询问服务器是否更新,减少流量
-
浏览器级缓存优化
- Vue:
<keep-alive>缓存组件状态,computed缓存运算结果 - React:
useCallback/useMemo缓存函数与计算,避免重复渲染
- Vue:
4. 代码拆分(SplitChunks)
-
第三方库拆分
node_modules依赖统一拆包,提取为vendors~*.js- 对于大型 UI 库(如 ElementUI),单独优先级最高,独立拆分,方便长期缓存
-
组件级别拆分
- 动态导入 (
import()+ Magic Comments):路由组件或业务组件按需加载 - 公共模块提取:
src/components下复用 ≥3 次的组件或工具函数抽取到commons~*.js
- 动态导入 (
5. 资源加载优化
-
关键资源预加载(Preload)
<link rel="preload" as="script|style|font" href="…">- Webpack 插件:PreloadWebpackPlugin 或者 Magic Comments(
/* webpackPreload: true */)
-
关键 CSS 内联
- 将关键路径(Above-the-Fold)CSS 提取并内联到
<style>中,减少首次请求数 - 通过 loader 配置
{ att: { rel: 'preload', as: 'style' } }
- 将关键路径(Above-the-Fold)CSS 提取并内联到
-
异步 JS 加载
<script src="…" async>:文件下载与 HTML 解析并行,执行顺序不保证<script src="…" defer>:文件下载并行,等 HTML 解析完毕再按顺序执行
6. 预渲染 & 预加载(以 Next.js 为例)
- 预渲染(Pre-rendering):在构建时(Static Generation)或请求时(Server-side Rendering)提前生成 HTML
- 预加载(Prefetch):利用框架能力,空闲时提前加载下一个路由所需资源,提升页面跳转速度
浏览器渲染原理
-
解析(Parsing)
- HTML → DOM 树;CSS → CSSOM 树
-
样式计算(Style Calculation)
- 将 CSSOM 与 DOM 合并,得到每个节点的最终样式
-
布局(Layout / Reflow)
- 确定每个节点的位置与尺寸
-
分层(Layering)
- 将页面分成若干绘制层,便于并行渲染与合成
-
绘制(Painting)
- 在主线程中逐层将内容绘制到位图(命令队列)
-
合成 & 光栅化(Composite & Rasterize)
- 合成线程(合成层级)将各层合并;GPU 进程负责光栅化并最终渲染到屏幕
以上各环节协同发力,即可有效缩短首屏加载时间,提升用户体验。
下面继续按思维导图的脉络,拆解三大模块的优化策略及原理:动画卡顿优化、应用状态管理优化 和 应用视图更新优化。
一、动画卡顿优化
目标:保持 60FPS+、减少主线程阻塞,让动画平滑无撕裂。
-
减少渲染主线程阻塞
-
异步/拆分微任务与宏任务
- 将大任务拆成小的异步任务(
setTimeout、Promise.then等),避免一次性占满主线程。
- 将大任务拆成小的异步任务(
-
Web Worker
- 把计算密集型逻辑挪到 Worker 线程,不影响主线程的渲染调度。
-
-
GPU 加速
- 利用 CSS transform/opacity 而非改变布局属性(如
width、top),触发布局(layout)时会导致重排(reflow)。 - GPU 级加速绘制(Composite),仅对图层进行合成,不走 JS→布局→绘制的主线程流程。
- 利用 CSS transform/opacity 而非改变布局属性(如
-
保持帧率 ≥ 60FPS
-
requestAnimationFrame- 浏览器在每一帧前回调,和屏幕刷新同步,避免抖动和丢帧。
-
限制计算复杂度
- 每帧内的 JS 运算量要可控,尽量常数级操作,避免 O(n²)/O(n·log n) 类型的逐帧重计算。
-
-
防抖与节流
-
节流(throttle)
- 对高频事件(scroll、resize、mousemove)以固定间隔触发回调。
-
防抖(debounce)
- 事件触发后延迟执行回调,清除旧调用,适合输入/搜索建议等场景。
-
-
压缩动画渲染时间
-
简化样式计算
- 读写 DOM 分离,避免“读后改”混合触发强制同步布局(layout thrashing)。
- 尽量少用会触发布局的属性读取(如
offsetWidth)。
-
CSS 动画替代 JS 动画
- 原生 CSS transition/animation 在浏览器优化更佳,不占用 JS 线程。
-
浏览器渲染管线回顾
- 构建 几何阶段(顶点着色、图元装配、光栅化)
- 光照阶段(片元着色器、光照计算、材质处理)
- 后处理阶段(后处理着色器、抗锯齿、色彩校正) GPU 加速正是利用了合成(Composite)与光栅化(Raster)进程,将动画层直接提交给 GPU 渲染。
二、应用状态管理优化
目标:按需加载、最小化不必要计算、避免多余状态更新。
-
Vue 生态
-
Vuex(State / Mutations / Actions / Getters / Modules)
- 支持模块化,按需加载模块,避免整个 store 的所有 getters 都被计算。
-
Pinia
- 原生支持 Tree-Shaking,无 Actions 概念,API 扁平,按需引入即可减少包体积。
-
-
React 生态
-
Redux(Actions / Store / Reducers)
- 较重的样板代码,但配合中间件和
reselect可以做“选择器缓存”避免多余计算。
- 较重的样板代码,但配合中间件和
-
Zustand
- 更轻量,基于 Hooks,支持细粒度订阅,组件仅订阅自己关心的 slice,更新时只触发相关组件重渲染。
-
要点:所有状态库都应尽量做到“按需订阅、最小更新”,并利用 Immutability + 纯函数减少副作用。
三、应用视图更新优化
目标:降低虚拟 DOM diff/真实 DOM 操作成本,减少不必要的重绘重排。
1. React 视图优化
-
Fiber 架构 & 虚拟 DOM
- 拆分渲染工作成可中断的小任务,利用空闲时间渐进式渲染。
-
性能相关 Hooks
useState异步更新原理:批量合并同一事件循环内的多次更新。- 组件级:
React.memo()对比 props,避免纯展示组件无意义重渲染。 - 函数级:
useCallback(fn, deps)缓存回调引用,配合React.memo子组件不会重复渲染。 - 数据级:
useMemo(valueFn, deps)缓存计算结果,无需在渲染期间重复执行。
-
合成事件
- React 将原生事件委托到根节点,减少事件绑定数量。
- 可通过
event.persist()在合成事件池中保留事件,或自行管理事件节流、去抖。
-
批量更新
- React 18+ 在多处(定时器、Promise 等)默认开启自动批量更新,减少多次渲染。
-
组件拆分 & 按需加载
- Code-Splitting:
React.lazy()+<Suspense>让路由/大组件按需异步加载,减少首屏 JS 体积。 - 虚拟滚动(长列表):仅渲染可视区 DOM 节点,滚动时动态添加/销毁行。
- Code-Splitting:
-
传统性能 API
shouldComponentUpdate(nextProps, nextState)(类组件)和key唯一标识,手动拦截不必要更新。
2. Vue 视图优化
-
响应式系统
- 精确依赖追踪,只有真正使用到的响应式数据变更才会触发对应组件更新。
-
虚拟 DOM
- diff 算法分层比对:静态节点提升、事件监听按需复用。
-
keep-alive缓存- 对长列表/路由视图组件做 LRU 缓存,切换时复用实例,保留状态,减少重新挂载开销。
-
按需组件拆分
- 同 React 一样,结合动态
import()或 Vue Router 的defineAsyncComponent,路由级别/组件级别都可异步加载代码。
- 同 React 一样,结合动态
以上三大模块优化互相配合:前端交互动画、状态流转 与 视图渲染,共同确保页面流畅、不卡顿、渲染开销最小化。
下面按 “技术栈” 思维导图的两条主干依次讲解:先看 Vue 从 2 → 3,再看 React 从 16 之前到 Fiber 架构下的新版本。
一、Vue2 Options → Vue3 Composition API
-
响应式系统:
Object.defineProperty→Proxy- Vue 2:基于
Object.defineProperty为每个属性定义 getter/setter,初始化时遍历所有数据,拦截读写以触发依赖收集和派发更新。 - Vue 3:用 ES2015 的
Proxy全面代理对象,拦截更丰富的操作(增删属性、遍历、in判断等),采集依赖更精准(深层对象也能被代理),并且可以提供shallowRef仅代理第一层。
- Vue 2:基于
-
虚拟 DOM 渲染与 Diff
-
同层比较 + 双端比对 +
key复用- 两棵旧/新 vnode 树同层比对,头尾双指针扫描,遇到移动或新增时,根据
key快速复用已有 DOM。
- 两棵旧/新 vnode 树同层比对,头尾双指针扫描,遇到移动或新增时,根据
-
AST 编译时静态标记
- 在模板编译阶段打上静态节点(
hoist)标签,运行时直接跳过对比,减少 diff 范围。
- 在模板编译阶段打上静态节点(
-
快速 Diff 算法
- 预处理:先比较左右相同前缀/后缀
- 中间乱序部分:寻找最长递增子序列(LIS),只移动不在 LIS 上的节点,其余节点复用或插入。
-
Block Tree
- Vue 3 引入 Block 概念,只对动态内容打补丁,静态内容直接复用,降低运行时开销。
-
-
打包与冷启动:Webpack → Vite
- Webpack:基于配置文件先生成 bundle,再做初始化、编译、输出,Dev 模式下启动慢、HMR 较重。
- Vite:开发模式下“无打包”(bundleless),用原生 ESM 在浏览器按需加载模块,只在请求时即时编译;借助
esbuild预构建依赖(超快)、内置缓存,大幅提升冷启动与 HMR 速度。 - 同时生产模式下仍可 Tree-Shaking,生成优化后的静态资产。
-
新指令和内置组件
v-memo:手动标记组件或节点,使其在依赖不变时跳过更新。<Suspense>:异步组件加载时支持占位与恢复,用于路由或按需加载场景。<Teleport>:将组件或 DOM 输出到当前组件树外的任意位置,常用于模态框、<body>级插槽等。
二、React 16 以前 → Fiber 架构
-
Fiber 机制:可中断、可调度的渲染
-
时间切片(Time Slicing)
- 将渲染工作拆分成多个小任务单元,按优先级调度,中断后留给更重要的更新或保持界面响应。
-
并发模式(Concurrent Mode)
- 允许 React 在后台准备多套 UI 树,并在合适时机切换,减少主线程卡顿和“白屏”体验。
-
-
更新调度流程
-
更新入队
- 所有状态更新(
setState、useState)会生成更新任务,挂到FiberRootNode的优先级队列中。
- 所有状态更新(
-
渲染阶段(Reconciliation)
beginWork(递):遍历旧 Fiber 树,与新元素比对,创建或复用子 Fiber,打上“插入”“删除”“更新”标记。completeWork(归):自底向上回溯,构建真实 DOM 节点与子树关系。
-
提交阶段(Commit)
- 将打好标记的更新批量提交:移除旧节点、插入新节点、执行生命周期钩子或 effect。
-
-
增量渲染与双缓存
-
增量渲染(Incremental Rendering)
- 渲染过程中可被打断,下一帧继续,保证主线程空闲时优先响应用户输入。
-
双缓存机制
- 每个 Fiber 节点持有两份指针:当前树(
current)和工作树(workInProgress),在渲染阶段对工作树操作,不影响当前界面的显示,等到 commit 再交换。
- 每个 Fiber 节点持有两份指针:当前树(
-
通过以上机制演进,Vue 3 与 React Fiber 都在「更精细的响应式依赖追踪」「更高效的 DOM diff」「可中断/并发渲染」「极快的开发模式启动」等方面实现了性能与开发体验的显著提升。