⚡ 30 秒速记
- 虚拟树是声明式界面的中间描述
- 渲染器把描述映射到具体宿主
- 更新比较与宿主操作各有成本
- 可预测组织复杂更新是主要收益
- 性能快慢必须结合实际变化范围
虚拟 DOM 的价值,是让业务描述界面应该是什么,再把怎样改页面交给渲染器。 中间描述可以被不同宿主处理,也便于统一管理组件和状态关系。更新时比较前后结果,只把需要的变化交给真实环境,但生成描述和比较并不是免费的。少量明确节点的手写更新可能很快,复杂页面则更需要可维护的统一机制,性能与工程收益要分别评估。
版本校准: 原理文章中的代码代表特定实现与写作时间。应用到当前项目时,应先确认浏览器、框架或工具的主版本,再区分稳定的规范语义、可变化的内部实现和项目自身约束。
# 快速搞定虚拟 DOM 的两个“大问题”
虚拟 DOM(Virtual DOM)
本质上是JS 和 DOM 之间的一个映射缓存,它在形态上表现为一个能够描述 DOM 结构及其属性信息的 JS 对象

就这个示例来说,你需要把握住以下两点:
- 虚拟 DOM 是 JS 对象
- 虚拟 DOM 是对真实 DOM 的描述
我们看看 React 中的虚拟 DOM 大致是如何工作的
- 挂载阶段,React 将结合 JSX 的描述,构建出虚拟 DOM 树,然后通过
ReactDOM.render实现虚拟 DOM 到真实 DOM 的映射(触发渲染流水线); - 更新阶段,页面的变化在作用于真实 DOM 之前,会先作用于虚拟
DOM,虚拟DOM将在 JS 层借助算法先对比出具体有哪些真实 DOM 需要被改变,然后再将这些改变作用于真实 DOM。
# 虚拟 DOM 是如何解决问题的

而在虚拟 DOM 的加持下,事情变成了这样:

注意图中的“模板”二字加了引号,这是因为虚拟 DOM 在实现上并不总是借助模板。比如 React 就使用了 JSX,前面咱们着重讲过,JSX 本质不是模板,而是一种使用体验和模板相似的 JS 语法糖
区别就在于多出了一层虚拟 DOM 作为缓冲层。这个缓冲层带来的利好是:当 DOM 操作(渲染更新)比较频繁时,它会先将前后两次的虚拟 DOM 树进行对比,定位出具体需要更新的部分,生成一个“补丁集”,最后只把“补丁”打在需要更新的那部分真实 DOM 上,实现精准的“差量更新”。这个过程对应的虚拟 DOM 工作流如下图所示:

注:图中的
diff 和 patch其实都是函数名,这些函数取材于一个独立的虚拟 DOM 库
还需要说明的一点是, 虚拟 DOM 和 Redux 一样,不依附于任何具体的框架。学习虚拟 DOM,实际上可以完全不借助 React;但学习 React,就必须了解虚拟 DOM
# React 选用虚拟 DOM,真的是为了更好的性能吗?
在整个 DOM 操作的演化过程中,主要矛盾并不在于性能,而在于开发者写得爽不爽,在于研发体验/研发效率。
虚拟 DOM 不是别的,正是前端开发们为了追求更好的研发体验和研发效率而创造出来的高阶产物。