【学习总结】相较于vue2,vue3的效率提升体现在哪些方面?

214 阅读4分钟

Vue 3 在性能优化方面有显著提升,有下面这几个点,可以展开讲一下

1.静态提升 2.预字符串化 3.缓存事件处理函数 4.BlockTree 5.PatchFlag

1.静态提升

在 Vue 2 里,每次更新组件时,静态节点(也就是渲染期间不会改变的节点)都会被重新创建。而在 Vue 3 中,静态节点会被提升到渲染函数外部,仅创建一次,之后更新时直接复用,从而减少了不必要的创建操作,提高了性能。

举例说明

假设我们有如下模板:

image.png

在没有静态提升的情况下,它对应的渲染函数是:

image.png

可以看到,在这段虚拟 DOM 的描述中存在两个 p 标签,一个是 纯静态的,而另一个拥有动态文本。当响应式数据 title 的值发生变 化时,整个渲染函数会重新执行,并产生新的虚拟 DOM 树。这个过程 有一个明显的问题,即纯静态的虚拟节点在更新时也会被重新创建一 次。很显然,这是没有必要的,所以我们需要想办法避免由此带来的 性能开销。而解决方案就是所谓的“静态提升”,即把纯静态的节点提 升到渲染函数之外,如下面的代码所示:

image.png

可以看到,当把纯静态的节点提升到渲染函数之外后,在渲染函数内只会持有对静态节点的引用。当响应式数据变化,并使得渲染函数重新执行时,并不会重新创建静态的虚拟节点,从而避免了额外的性能开销。

虽然包含动态绑定的节点本身不会被提升,但是该动态节点上仍 然可能存在纯静态的属性,如下面的模板所示

image.png

在上面这段模板中,p 标签存在动态绑定的文本内容,因此整个节 点都不会被静态提升。但该节点的所有 props 都是静态的,因此在最 终生成渲染函数时,我们可以将纯静态的 props 提升到渲染函数之 外,如下面的代码所示:

image.png

这样做同样可以减少创建虚拟 DOM 产生的开销以及内存占用。

2.预字符串化

Vue 3 会对静态内容进行预字符串化处理。也就是把静态的 HTML 内容提前转换为字符串,在渲染时直接使用这些字符串,减少了运行时的 DOM 操作,从而提升了渲染速度。

基于静态提升,我们还可以进一步采用预字符串化的优化手段。 预字符串化是基于静态提升的一种优化策略。静态提升的虚拟节点或 虚拟节点树本身是静态的,那么,能否将其预字符串化呢?如下面的 模板所示

image.png

假设上面的模板中包含大量连续纯静态的标签节点,当采用了静 态提升优化策略时,其编译后的代码如下:

image.png

预字符串化能够将这些静态节点序列化为字符串,并生成一个 Static 类型的 VNode:

image.png

image.png

这么做有几个明显的优势。

  • 大块的静态内容可以通过 innerHTML 进行设置,在性能上具有 一定优势。
  • 减少创建虚拟节点产生的性能开销。
  • 减少内存占用。

3.缓存内联事件处理函数

假设模板内容如下

image.png

对应的渲染函数如下

image.png

很显然,每次重新渲染时(即 render 函数重新执行时),都会 为 Comp 组件创建一个全新的 props 对象。同时,props 对象中 onChange 属性的值也会是全新的函数。这会导致渲染器对 Comp 组 件进行更新,造成额外的性能开销。为了避免这类无用的更新,我们 需要对内联事件处理函数进行缓存,如下面的代码所示:

image.png

渲染函数的第二个参数是一个数组 cache,该数组来自组件实 例,我们可以把内联事件处理函数添加到 cache 数组中。这样,当渲 染函数重新执行并创建新的虚拟 DOM 树时,会优先读取缓存中的事件 处理函数。这样,无论执行多少次渲染函数,props 对象中 onChange 属性的值始终不变,于是就不会触发 Comp 组件更新了。

4.BlockTree

5.PatchFlag