🌙 React diff算法
🌙 DOM 树的遍历
function diff (oldNode, newNode) {
const patches = [];
walk(oldNode, newNode, patches, 0); // 进行深度优先遍历
return patches;
}
function walk(oldNode, newNode, patches, index) {
if (newNode === oldNode) {
return
}
const patch = { type: 'update', vNode: newNode };
const oldChildren = oldNode.children;
const newChildren = newNode.children;
const oldLen = oldChildren.length;
const newLen = newChildren.length;
const len = oldLen > newLen ? oldLen : newLen;
// 找到对应位置的子节点进行比对
for (let i = 0; i < len; i++) {
const oldChild = oldChildren[i];
const newChild = newChildren[i];
index++;
// 相同节点进行比对
walk(oldChild, newChild, patches, index);
if (isArray(oldChild.children)) {
index += oldChild.children.length;
}
}
if (patch) {
patches[index] = patch;
}
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
🌙 VDOM 节点的对比
上面代码只是对 VDOM 进行了简单的深度优先遍历,在遍历中,还需要对每个 VDOM 进行一些对比,具体分为以下几种情况:
- 1.旧节点不存在,插入新节点;新节点不存在,删除旧节点
- 2.新旧节点如果都是 VNode,且新旧节点 tag 相同
- 对比新旧节点的属性
- 对比新旧节点的子节点差异,通过 key 值进行重排序,key 值相同节点继续向下遍历
- 3.新旧节点如果都是 VText,判断两者文本是否发生变化
- 4.其他情况直接用新节点替代旧节点