react原理之diff策略+diff过程

114 阅读2分钟

前言

上篇文章提过什么是协调:
Virtual DOM是一种编程概念,在这个概念里,UI以一种理想化的,或者说“虚拟的”表现形式被保存在内存中,并通知reactDom等类库使之与“真实的”DOM同步,这一过程就叫协调。

reconciliation协调

设计动力

在某一时间节点调用 React 的 render() 方法,
会创建一棵由 React 元素组成的树。
在下一次 state 或props 更新时,
相同的 render() 方法会返回一棵不同的树。
React 需要基于这两棵树之间的差别来判断
如何有效率的更新 UI 以保证当前 UI 与最新的树保持同步。

这个算法问题有一些通用的解决方案,
即生成将一棵树转换成另一棵树的最小操作数。
然而,即使在最前沿的算法中,
该算法的复杂程度为 O(n 3 ),其中 n 是树中元素的数量。

如果在 React 中使用了该算法,
那么展示 1000 个元素所需要执行的计算量将在十亿的量级范围。
这个开销实在是太过高昂。
于是 React 在以下两个假设的基础之上提出了一套 O(n) 的启发式算法:

  1. 两个不同类型的元素会产生出不同的树

  2. 开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定;

在实践中,我们发现以上假设在几乎所有实用的场景下都成立。

diffing算法

算法复杂度O(n)

diff 策略

  1. 同级比较,Web UI 中 DOM 节点跨层级的移动操作特别少,可以忽略不计。

  2. 拥有不同类型的两个组件将会生成不同的树形结构。

例如:
div->p, CompA->CompB

  1. 开发者可以通过 key prop 来暗示哪些子元素在不同的渲染下能保持稳定。

diff过程

比对两个虚拟dom时会有三种操作:删除、替换和更新

vnode是现在的虚拟dom,newVnode是新虚拟dom。

删除:newVnode不存在时。

替换:vnode和newVnode类型不同或key不同时。

更新:有相同类型和key但vnode和newVnode不同时。

在实践中也证明这三个前提策略是合理且准确的,它保证了整体界面构建的性能。