React 15 的调和

知识点:

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)。