Vue 是如何将一份模板转换为真实的 DOM 节点的,又是如何高效地更新这些节点的呢?我们接下来就将尝试通过深入研究 Vue 的内部渲染机制来解释这些问题。
虚拟 DOM
你可能已经听说过“虚拟 DOM”的概念了,Vue 的渲染系统正是基于这个概念构建的。
虚拟 DOM (Virtual DOM,简称 VDOM) 是一种编程概念,意为将目标所需的 UI 通过数据结构“虚拟”地表示出来,保存在内存中,然后将真实的 DOM 与之保持同步。这个概念是由 React 率先开拓,随后在许多不同的框架中都有不同的实现,当然也包括 Vue。
与其说虚拟 DOM 是一种具体的技术,不如说是一种模式,所以并没有一个标准的实现。我们可以用一个简单的例子来说明:
const vnode = {
type: 'div',
props: {
id: 'hello'
},
children: [
/* 更多 vnode */
]
}
这里所说的 vnode 即一个纯 JavaScript 的对象 (一个“虚拟节点”),它代表着一个 <div> 元素。它包含我们创建实际元素所需的所有信息。它还包含更多的子节点,这使它成为虚拟 DOM 树的根节点。
一个运行时渲染器将会遍历整个虚拟 DOM 树,并据此构建真实的 DOM 树。这个过程被称为挂载 (mount)。
如果我们有两份虚拟 DOM 树,渲染器将会有比较地遍历它们,找出它们之间的区别,并应用这其中的变化到真实的 DOM 上。这个过程被称为更新 (patch),又被称为“比对”(diffing) 或“协调”(reconciliation)。
虚拟 DOM 带来的主要收益是它让开发者能够灵活、声明式地创建、检查和组合所需 UI 的结构,同时只需把具体的 DOM 操作留给渲染器去处理。
渲染管线
从高层面的视角看,Vue 组件挂载时会发生如下几件事:
1.编译:Vue 模板被编译为渲染函数:即用来返回虚拟 DOM 树的函数。这一步骤可以通过构建步骤提前完成,也可以通过使用运行时编译器即时完成。
2.挂载:运行时渲染器调用渲染函数,遍历返回的虚拟 DOM 树,并基于它创建实际的 DOM 节点。这一步会作为响应式副作用执行,因此它会追踪其中所用到的所有响应式依赖。
3.更新:当一个依赖发生变化后,副作用会重新运行,这时候会创建一个更新后的虚拟 DOM 树。运行时渲染器遍历这棵新树,将它与旧树进行比较,然后将必要的更新应用到真实 DOM 上去。
![](data:image/png;base64,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)
模板 vs. 渲染函数
Vue 模板会被预编译成虚拟 DOM 渲染函数。Vue 也提供了 API 使我们可以不使用模板编译,直接手写渲染函数。在处理高度动态的逻辑时,渲染函数相比于模板更加灵活,因为你可以完全地使用 JavaScript 来构造你想要的 vnode。
那么为什么 Vue 默认推荐使用模板呢?有以下几点原因:
1.模板更贴近实际的 HTML。这使得我们能够更方便地重用一些已有的 HTML 代码片段,能够带来更好的可访问性体验、能更方便地使用 CSS 应用样式,并且更容易使设计师理解和修改。
2.由于其确定的语法,更容易对模板做静态分析。这使得 Vue 的模板编译器能够应用许多编译时优化来提升虚拟 DOM 的性能表现 (下面我们将展开讨论)。
在实践中,模板对大多数的应用场景都是够用且高效的。渲染函数一般只会在需要处理高度动态渲染逻辑的可重用组件中使用。想了解渲染函数的更多使用细节可以去到渲染函数 & JSX 章节继续阅读。
带编译时信息的虚拟 DOM
虚拟 DOM 在 React 和大多数其他实现中都是纯运行时的:更新算法无法预知新的虚拟 DOM 树会是怎样,因此它总是需要遍历整棵树、比较每个 vnode 上 props 的区别来确保正确性。另外,即使一棵树的某个部分从未改变,还是会在每次重渲染时创建新的 vnode,带来了大量不必要的内存压力。这也是虚拟 DOM 最受诟病的地方之一:这种有点暴力的更新过程通过牺牲效率来换取声明式的写法和最终的正确性。
但实际上我们并不需要这样。在 Vue 中,框架同时控制着编译器和运行时。这使得我们可以为紧密耦合的模板渲染器应用许多编译时优化。编译器可以静态分析模板并在生成的代码中留下标记,使得运行时尽可能地走捷径。与此同时,我们仍旧保留了边界情况时用户想要使用底层渲染函数的能力。我们称这种混合解决方案为带编译时信息的虚拟 DOM。
下面,我们将讨论一些 Vue 编译器用来提高虚拟 DOM 运行时性能的主要优化:
静态提升
在模板中常常有部分内容是不带任何动态绑定的:
<div>
<div>foo</div> <!-- 需提升 -->
<div>bar</div> <!-- 需提升 -->
<div>{{ dynamic }}</div>
</div>
foo 和 bar 这两个 div 是完全静态的,没有必要在重新渲染时再次创建和比对它们。Vue 编译器自动地会提升这部分 vnode 创建函数到这个模板的渲染函数之外,并在每次渲染时都使用这份相同的 vnode,渲染器知道新旧 vnode 在这部分是完全相同的,所以会完全跳过对它们的差异比对。
此外,当有足够多连续的静态元素时,它们还会再被压缩为一个“静态 vnode”,其中包含的是这些节点相应的纯 HTML 字符串。(示例)。这些静态节点会直接通过 innerHTML 来挂载。同时还会在初次挂载后缓存相应的 DOM 节点。如果这部分内容在应用中其他地方被重用,那么将会使用原生的 cloneNode() 方法来克隆新的 DOM 节点,这会非常高效。
更新类型标记
对于单个有动态绑定的元素来说,我们可以在编译时推断出大量信息:
<!-- 仅含 class 绑定 -->
<div :class="{ active }"></div>
<!-- 仅含 id 和 value 绑定 -->
<input :id="id" :value="value">
<!-- 仅含文本子节点 -->
<div>{{ dynamic }}</div>
在为这些元素生成渲染函数时,Vue 在 vnode 创建调用中直接编码了每个元素所需的更新类型:
createElementVNode("div", {
class: _normalizeClass({ active: _ctx.active })
}, null, 2 /* CLASS */)
最后这个参数 2 就是一个更新类型标记 (patch flag)。一个元素可以有多个更新类型标记,会被合并成一个数字。运行时渲染器也将会使用位运算来检查这些标记,确定相应的更新操作:
if (vnode.patchFlag & PatchFlags.CLASS /* 2 */) {
// 更新节点的 CSS class
}
位运算检查是非常快的。通过这样的更新类型标记,Vue 能够在更新带有动态绑定的元素时做最少的操作。
Vue 也为 vnode 的子节点标记了类型。举例来说,包含多个根节点的模板被表示为一个片段 (fragment),大多数情况下,我们可以确定其顺序是永远不变的,所以这部分信息就可以提供给运行时作为一个更新类型标记。
export function render() {
return (_openBlock(), _createElementBlock(_Fragment, null, [
/* children */
], 64 /* STABLE_FRAGMENT */))
}
运行时会完全跳过对这个根片段中子元素顺序的重新协调过程。
树结构打平
再来看看上面这个例子中生成的代码,你会发现所返回的虚拟 DOM 树是经一个特殊的 createElementBlock() 调用创建的:
export function render() {
return (_openBlock(), _createElementBlock(_Fragment, null, [
/* children */
], 64 /* STABLE_FRAGMENT */))
}
这里我们引入一个概念“区块”,内部结构是稳定的一个部分可被称之为一个区块。在这个用例中,整个模板只有一个区块,因为这里没有用到任何结构性指令 (比如 v-if 或者 v-for)。
每一个块都会追踪其所有带更新类型标记的后代节点 (不只是直接子节点),举例来说:
<div> <!-- root block -->
<div>...</div> <!-- 不会追踪 -->
<div :id="id"></div> <!-- 要追踪 -->
<div> <!-- 不会追踪 -->
<div>{{ bar }}</div> <!-- 要追踪 -->
</div>
</div>
编译的结果会被打平为一个数组,仅包含所有动态的后代节点:
div (block root)
- div 带有 :id 绑定
- div 带有 {{ bar }} 绑定
当这个组件需要重渲染时,只需要遍历这个打平的树而非整棵树。这也就是我们所说的树结构打平,这大大减少了我们在虚拟 DOM 协调时需要遍历的节点数量。模板中任何的静态部分都会被高效地略过。
v-if 和 v-for 指令会创建新的区块节点:
<div> <!-- 根区块 -->
<div>
<div v-if> <!-- if 区块 -->
...
<div>
</div>
</div>
一个子区块会在父区块的动态子节点数组中被追踪,这为他们的父区块保留了一个稳定的结构。
对 SSR 激活的影响
更新类型标记和树结构打平都大大提升了 Vue SSR 激活的性能表现:
1.单个元素的激活可以基于相应 vnode 的更新类型标记走更快的捷径。
2.在激活时只有区块节点和其动态子节点需要被遍历,这在模板层面上实现更高效的部分激活。