# 前言
上一节,我们介绍了关于新旧子节点不同为数组的情况下的更新过程,下面将接着上节的内容继续介绍如果子节点都是数组的情况,那么更新过程会变成什么样呢?
# 1. 从头比对
Vue 3 的 diff 算法第一步就是进行新老节点从头比对的方式来判断是否是同类型的节点:
const patchKeyedChildren = (c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) => {
let i = 0
const l2 = c2.length
// 旧节点的尾部标记位
let e1 = c1.length - 1
// 新节点的尾部标记位
let e2 = l2 - 1
// 从头部开始比对
// (a b) c
// (a b) d e
while (i <= e1 && i <= e2) {
const n1 = c1[i]
const n2 = (c2[i] = optimized
? cloneIfMounted(c2[i] as VNode)
: normalizeVNode(c2[i]))
// 如果是 sameVnode 则递归执行 patch
if (isSameVNodeType(n1, n2)) {
patch(n1, n2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized)
} else {
break
}
i++
}
}
@前端进阶之旅: 代码已经复制到剪贴板
这里有几个变量需要说明一下:
i代表的是头部的标记位;e1代表的是旧的子节点的尾部标记位;e2代表的是新的子节点的尾部标记位。
从头比对就是通过不断移动 i 这个头部标记位来判断对应的节点是否是 sameVnode。如果是,则进行递归 patch 操作,递归 patch 就是继续进入到我们上一小节的内容。如果不满足条件,则退出头部比对,进入从尾比对流程。
# 2. 从尾比对
const patchKeyedChildren = (c1, c2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized) => {
let i = 0
const l2 = c2.length
// 旧节点的尾部标记位
let e1 = c1.length - 1
// 新节点的尾部标记位
let e2 = l2 - 1
// 从头部开始比对
// ...
// 从尾部开始比对
// a (b c)
// d e (b c)
while (i <= e1 && i <= e2) {
const n1 = c1[e1]
const n2 = (c2[i] = optimized
? cloneIfMounted(c2[i] as VNode)
: normalizeVNode(c2[i]))
// 如果是 sameVnode 则递归执行 patch
if (isSameVNodeType(n1, n2)) {
patch(n1, n2, container, parentAnchor, parentComponent, parentSuspense, isSVG, optimized)
} else {
break
}
e1--
e2--
}
}
