【React】diff算法

796 阅读3分钟

1.diff算法


作用:计算出Virtual DOM中真正变化的部分,并只针对该部分进行原生DOM操作,而非渲染整个页面,从而达到高效渲染

2.diff算法策略

  • UI中DOM节点跨层级的移动操作特别少,可以忽略不计——跨级移动(tree diff)

  • 拥有相同类的两个组件将会拥有类似的树形结构,拥有不同类的两个组件则拥有不同的树形结构——同类相似(component diff)

  • 同一层级的一组子节点,可以通过唯一id进行区分——唯一区分(element diff)

2.1 tree diff

分层比较,两棵树只会针对同一层级的DOM节点进行比较,即同一父节点下的所有子节点。如果发现节点A已经不存在时,则对应的删除该节点及其所有子节点


如上图情况,diff执行情况:create A ——> create B ——> create C ——> delete A,这种跨级的移动的操作很影响React性能,不建议这么做

2.2 component diff

组件之间的比较:

  • 如果是同一类型:继续比较Virtual DOM树

    注意:如果明确知道Virtual DOM没有变化,则无需继续比较Virtual DOM树从而节省了时间。React允许我们通过shouldComponentUpdate()来判断该组件是否需要进行diff算法分析

  • 如果是不同类型:替换整个组件下的所有子组件


当组件D变为组件G时,即使两个组件的结构类似,但当React判断D和G是不同类型,则不会继续比价二者的内部结构,直接删除组件D,重新创建组件G及其子元素

diff执行情况:delete D ——> create G ——> create E ——> create F

2.3 element diff

当节点处于同一层级时,diff提供了3种节点的操作方法:

  • INSERT_MARKUP(插入)

  • MOVE_EXISTING(移动)

  • REMOVE_NODE(删除)

1)对节点进行diff差异化对比


具体流程如下表所示:

节点NI(newIndex)OI(oldIndex)MI(maxIndex)操作
B010OI>MI,MI=OI
A101OI<MI,A——>当前NI位置
D231OI>MI,MI=OI
C323OI<MI,C——>当前NI位置
  • NI(newIndex):节点在新集合中的下标

  • OI(oldIndex):节点在老集合中的下标

  • MI(maxIndex):在新集合访问过的节点中,其对应在老集合中的最大下标值

2)创建、移动、删除节点

节点NI(newIndex)OI(oldIndex)MI(maxIndex)操作
B010OI>MI,MI=OI
E1-1OI不存在,在当前NI位置创建节点E
C221OI>MI,MI=OI
A302OI<MI,A——>当前NI位置
  • NI(newIndex):节点在新集合中的下标

  • OI(oldIndex):节点在老集合中的下标

  • MI(maxIndex):在新集合访问过的节点中,其对应在老集合中的最大下标值

根据上面两表所示的操作流程可知,在操作栏位只比较OI(oldIndex)和MI(maxIndex)

  • OI>MI,MI=OI

  • OI=MI,不操作

  • OI<MI,将当前节点移动到当前的NI位置

  • OI不存在时,在当前NI位置创建当前节点(如节点E)