知识点:
Diff 算法过程
- 分层对比
- 类型一致才对比
- 使用 key 尽可能复用节点
什么是调和(Reconciliation)
React 官方文档如是说:
Virtual DOM 是一种编程概念。在这个概念里,UI 以一种理想化的,或者说“虚拟的”表现形式被保存于内存中,并通过如 ReactDOM 等类库使之与“真实的” DOM 同步。这一过程叫作协调(调和)。
Diff 则是调和过程最重要部分。
Diff 算法
生成将一棵树转换成另一棵树的最小操作次数的最优算法,复杂程度仍为 O(n3) ,其中 n 是树中元素的数量。
如果在 React 中使用该算法,那么展示 1000 个元素则需要 10 亿次的比较。这个开销实在是太过高昂。于是 React 在以下两个假设的基础之上提出了一套 O(n) 的启发式算法:
- 两个不同类型的元素会产生出不同的树;
- 开发者可以通过设置 key 属性,来告知渲染哪些子元素在不同的渲染下可以保存不变;
React Diff 算法的三个要点
Diff 算法性能突破的关键点在于“分层对比”
Diff 算法只从跟元素开始对比同一层级的节点。如果节点 A 被移动到其他层,diff 算法会认为节点 A 已经不存在了;而在节点 A 的位置则会认为是新节点,重新创建。虽然这个销毁和新建的过程耗费性能,但此种跨层次的移动毕竟比较少,为了降低算法复杂度,React 选择忽略。这也提醒我们,尽量保持 DOM 结构的稳定,最好不要跨层级移动 DOM。
类型一致的节点才有继续 Diff 的必要性
对于类型不一致节点,diff 算法将认为他们是不同的节点,并且其子节点也将不再对比。key 属性的设置,可以帮我们尽可能重用同一层级内的节点
对于同一层级的节点,满足上面两个条件,只要 key 相同就认为是同一个节点,在比较的过程中,只要更新节点的属性即可,实现节点的复用。
传统 Diff 算法为什么是 O(n3)
Diff 算法是找出 Tree Edit Distance,在 Tree Edit Distance 算法研究中,这篇论文 是将其优化到 O(n3)。
React Diff 算法并不是在传统 Diff 算法进行优化,而是针对 DOM 结构特别这个特殊场景,只进行“分层对比”,因为时间复杂度只为 O(n)。