17.2.3 Fragment 的稳定性
Fragment 内部的
dynamicChildren仍然可能数量或顺序不一致,此时只能放弃靶向更新、回退传统 Diff;而「稳定」的 Fragment 则可以继续享受优化。
一、什么样的 Fragment 不稳定
结构不稳定从结果上看,指更新前后一个 Block 的
dynamicChildren数组中收集的动态节点的数量或顺序不一致。
v-for 渲染出的 Fragment 就属于这一类:列表长度变化时,Fragment 的 dynamicChildren 长度随之变化。
二、处理办法
- 放弃「根据
dynamicChildren做靶向更新」的思路,回退到传统虚拟 DOM 的 Diff; - 具体做法是直接使用 Fragment 的
children,而不是它的dynamicChildren来做 Diff:
// 不用 dynamicChildren,改用 children 走传统 Diff
patchChildren(n1, n2, el)
三、Fragment 的 children 仍可由 Block 组成
const block = {
tag: Fragment,
children: [
{ tag: 'p', children: item, dynamicChildren: [/* ... */], patchFlags: PatchFlags.TEXT },
{ tag: 'p', children: item, dynamicChildren: [/* ... */], patchFlags: PatchFlags.TEXT },
],
}
Fragment 的子节点本身可以是由 Block 组成的数组,于是当 Fragment 的子节点进行更新时,仍然可以恢复优化模式(在子 Block 内部继续只遍历 dynamicChildren)。
四、哪些 Fragment 是稳定的
v-for的表达式是常量时:<p v-for="n in 10"></p> <p v-for="s in 'abc'"></p>无论怎样更新,渲染出的 Fragment 都不会变化,因此是稳定的。
模板存在多个根节点时必须用 Fragment 描述:
<template> <div></div> <p></p> <i></i> </template>这种用于描述多根节点模板的 Fragment 也是稳定的。
稳定的 Fragment 会带
STABLE_FRAGMENT标志,渲染器可以继续按优化路径处理;一旦发现结构不稳定,就整块退回普通 Diff。
相关
- 17.2.2 带有 v-for 指令的节点:Fragment Block 的引入
- 17.3 静态提升:不再收集动态节点之后,还有哪些减少虚拟 DOM 开销的手段