# React Diff算法
假设在 Real DOM 中存在下面这几个兄弟节点:【A、B、C、D、E、F、G】
Virtual Dom中的节点为:【D、A、G、F、K、E】
Diff算法过程:
遍历 Virtual DOM
首先,第1个节点除非要被移除,否则不会被移动,于是首节D不动
遍历到节点A,在Real Dom中节点A移动到节点D之后(使用DOM元素的
insertBefore
方法),这是第1次操作DOM 此时Real DOM为【B、C、D、A、E、F、G】遍历到节点G,由于在Real DOM 中节点G在节点A(上一个遍历到的节点)之后,与 Virtual DOM 顺序相同,因此不动 此时Real DOM为【B、C、D、A、E、F、G】
遍历到节点F,由于在 Real DOM 中节点F在节点G(上一个遍历到的节点)之前,与 Virtual DOM 顺序不同,因此我们把节点F移动到节点G之后。这是第2次操作DOM 此时 Real DOM 为 【B、C、D、A、E、G、F】
遍历到节点K,在 Real DOM 中不存在K节点,我们创建它,并放在节点F(上一个遍历到的节点)之后。这是第3次操作DOM 此时 Real DOM 为 【B、C、D、A、E、G、F、K】
遍历到节点E,由于节点K(上一个遍历到的节点)是新创建的节点,因此我们直接把节点E移动到节点K之后。这是第4次操作DOM 此时 Real DOM 为 【B、C、D、A、G、F、K、E】
遍历real Dom
// virtual Dom【D、A、G、F、K、E】 // Real DOM 为 【B、C、D、A、G、F、K、E】
- 移除节点B和节点C。第5、6次操作DOM
Real DOM 为【D、A、G、F、K、E】
于是,如果不考虑节点的移除和创建,我们可以推导出什么样的重新排序对这套 DOM Diff 算法最不利。最不利的结果无非就是除了首个节点外,其它所有节点都需要移动,对于有 N 个节点的数组,总共移动了 N-1 次。
例子1:考虑这个序列【A、B、C、D】,如果想变成【D、C、B、A】,应该是什么样的过程:
节点D是首个节点,不执行移动。
节点C移动到节点D后面:【A、B、D、C】;
节点B移动到节点C后面:【A、D、C、B】;
节点A移动到节点B后面:【D、C、B、A】。
dom-diff
一共3步,正是 N-1。所以,可以确定的是,如果末尾的节点移动到了首位,就会引起最不利的 DOM Diff 结果。
例子2:这个序列【A、B、C、D】,变成【D、A、B、C】。我们一眼看上去就知道,只要把节点D移动到首位就可以了,但是我们看 React 它会怎么做:
节点D是首个节点,不执行移动。
节点A移动到节点D后面:【B、C、D、A】;
节点B移动到节点A后面:【C、D、A、B】;
节点C移动到节点B后面:【D、A、B、C】。
dom-diff还是 N-1,可见首个节点不执行移动这个特性,导致了只要把末尾节点移动到首位,就会引起 N-1 这种最坏的 DOM Diff 过程,所以大家要尽可能避免这种重排序。