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) | 操作 |
|---|---|---|---|---|
| B | 0 | 1 | 0 | OI>MI,MI=OI |
| A | 1 | 0 | 1 | OI<MI,A——>当前NI位置 |
| D | 2 | 3 | 1 | OI>MI,MI=OI |
| C | 3 | 2 | 3 | OI<MI,C——>当前NI位置 |
NI(newIndex):节点在新集合中的下标
OI(oldIndex):节点在老集合中的下标
MI(maxIndex):在新集合访问过的节点中,其对应在老集合中的最大下标值
2)创建、移动、删除节点
| 节点 | NI(newIndex) | OI(oldIndex) | MI(maxIndex) | 操作 |
|---|---|---|---|---|
| B | 0 | 1 | 0 | OI>MI,MI=OI |
| E | 1 | - | 1 | OI不存在,在当前NI位置创建节点E |
| C | 2 | 2 | 1 | OI>MI,MI=OI |
| A | 3 | 0 | 2 | OI<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)