虚拟 DOM 解决的核心问题是频繁零散 DOM 操作引发的性能雪崩,它通过内存中批量比对与最小化更新来减少重排重绘、屏蔽手动 diff 复杂性,并以 JS 计算换低频精准 DOM 调用,但并非在所有场景下都更快。

虚拟 DOM 解决的核心问题,是频繁、零散的 DOM 操作引发的性能雪崩——它不是让单次操作变快,而是让“一连串操作”变得可控、可优化。
避免高频重排重绘
浏览器每次修改真实 DOM 的几何属性(比如宽高、位置、显示隐藏),都会触发重排;改颜色、背景等样式则触发重绘。而重排成本极高,尤其在节点多时,可能牵动整棵树重新计算布局。
- 直接操作 DOM 时,连续写 10 次
element.style.color或element.innerHTML,浏览器可能执行 10 次重绘甚至重排; - 虚拟 DOM 把这些变更先记在内存里,等所有状态更新完,再一次性比对出真正要改的节点,最后只做一次或少数几次真实 DOM 操作;
- 这就把原本可能触发 10 次渲染流水线的动作,压缩成 1 次,大幅降低主线程与渲染线程的切换开销。
屏蔽手动 diff 的复杂性
当 UI 数据变化(比如列表项增删、排序、局部更新),开发者若直接操作真实 DOM,就得自己判断:哪些节点该复用?哪些要新增?哪些该移除?哪些文本只需替换?这在嵌套深、逻辑复杂的组件中极易出错或遗漏。
- 虚拟 DOM 内置 diff 算法(如 React 的 Fiber、Vue 的 patch),自动比对新旧树结构,只定位到真正发生变化的最小粒度(例如仅更新某个
<span>的文本,而非整个列表); - 它保留了节点身份(通过 key)、复用已有 DOM 元素(避免重复创建销毁),还能维持表单输入框的焦点、滚动位置等用户态信息;
- 相当于把“该不该更新、怎么更新”这个高难度决策,交给框架统一处理。
用 JS 内存计算换 DOM 低频调用
DOM 节点不是普通 JS 对象,它背后绑着浏览器渲染引擎、样式计算、布局树、图层合成等重型机制。每次访问 offsetHeight、getBoundingClientRect 或设置 style,都可能强制同步触发重排。
- 虚拟 DOM 是纯 JS 对象(如
{ type: 'div', props: { id: 'app' }, children: [...] }),创建、遍历、修改都在 JS 引擎内完成,没有跨线程通信开销; - 所有中间计算(生成新树、diff、打补丁)都发生在内存中,等结果确定后,才批量调用
document.createElement、node.textContent = ...这类真实 DOM API; - 本质是“用空间(内存中的虚拟树)和时间(JS 计算)换 DOM 的低频、精准调用”。
它并不总是更快
虚拟 DOM 是为复杂交互场景设计的权衡方案,不是万能加速器。
- 首次渲染时,它多了一层 JS 对象构建和 diff 计算,比直接 innerHTML 稍慢;
- 简单静态页面或只读内容,直接操作 DOM 更轻量、更直接;
- 过度嵌套、无 key、或频繁 forceUpdate,反而会让 diff 失效,导致不必要的全量更新。

















