“调和”和 Diff
“调和”又译为“协调”
Virtual DOM 是一种编程概念。在这个概念里, UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的”DOM同步,这一过程叫作协调(调和)。
所以调和过程并不能和 Diff 划等号
- 调和是“使一致”的过程
- Diff 是“找不同”的过程
React 的源码划分了
- Core
- Renderer
- Reconciler
- 调和器的源码位于
src/renderers/shared/stack/reconciler
- 调和器所做的工作包括组件的挂载、卸载、更新等过程
- 调和器的源码位于
Diff 是调和过程中最具代表性的一环
根据 Diff 实现形式的不同,调和过程划分为
- React15 代表的栈调和
- React16 代表的 Fiber 调和
Diff 策略的设计思想
要想找出两个树结构之间的不同:
传统的计算方法是通过循环递归进行树节点为的一一对比
- 算法的时间复杂度是
- 对浏览器来说,仍然意味着一场性能灾难
- OJ 中相对理想的时间复杂度是 或 ,当复杂度攀升至 就要寻找性能优化手段
React 团队把复杂度降低设立两个大前提
- 若两个组件属于同一个类型,它们将拥有相同的 DOM 树形结构
- 处于同一层级的一组子节点,可通过设置 Key 作为唯一标识,从而维持各个节点在不同渲染过程中的稳定性
还有一个与实践紧密的规律
- Diff 算法性能突破的关键点在于“分层对比”
- DOM 节点之间跨层级操作不多,同层级操作是主流
- Diff 过程只先对相同层级的节点对比
- 对于跨层级的操作,只不能分辨移动的行为。
只能移除出子树节进行销毁,移入子树作新增。销毁加上重建的代价
- 类型一致的节点才有继续 Diff 的必要性
- 若两个组件属于同一个类型,它们将拥有相同的 DOM 树形结构
- 减少递归“一刀切”策略:类型的一致性关键字来递归的必要性
- React 认为,只有同类型的组件,才有进一步对比的必要性
- React 认为,只有同类型的组件,才有进一步对比的必要性
- key 属性的设置,可以尽可能重用同一层级内的节点
- 处于同一层级的一组子节点,可通过设置 Key 作为唯一标识,从而维持各个节点在不同渲染过程中的稳定性
重用节点的好帮手:key 属性帮 React “记住”节点
key 是用来帮助 React 识别哪些内容被更改、添加或者删除。key 需要写在用数组渲染出来的元素内部,并且需要赋予其一个稳定的值。稳定在这里很重要,因为如果 key 值发生了变更,React 则会触发 UI 的重渲染。这是一个非常有用的特性。
- 解决了同一层级下节点的重用问题:
- 原本新增 1 个节点就能搞定的事情,现在却又是删除又是重建
- 插入节点的形式是高频操作,key 属性来帮助重用节点
- 解决了同一层级下节点的重用问题: