详解Vue3.0对虚拟Dom的优化

您所在的位置:网站首页 vue怎么创建虚拟dom 详解Vue3.0对虚拟Dom的优化

详解Vue3.0对虚拟Dom的优化

2023-10-08 03:30| 来源: 网络整理| 查看: 265

一、什么是Virtual(虚拟)DOM?

VirtualDOM 是对DOM的抽象,本质上它是个JavaScript对象,用一句话来简单理解,DOM上的内容较繁杂,这个对象就是更加轻量级的对DOM的描述。通过JavaScript对象表示DOM信息和结构,更新后使之与真实dom保持同步,同步的过程就是协调,核心是 diff算法,不太了解diff算法的同学可以检索相关文章进行学习。

二、Vue 为什么采用Virtual DOM? 创建真实DOM的代价高: 真实的DOM节点node实现的属性很多,而vnod 仅仅实现一些必要的属性,相比起来,创建一个vnode 的成本比较低。 触发多次浏览器重绘及回流: 使用vnode,相当于加了一个缓冲,让一次数据变动所带来的所有node变化,先在vnode中进行修改,然后diff之后对所有产生差异的节点集中一次对 DOM Tree 进行修改,以减少浏览器的重绘及回流。 虚拟dom由于本质是一个JS对象,因此天生具备跨平台的能力,可以实现在不同平台的准确显示。 VirtualDOM在性能上的收益并不是最主要的,更重要的是它使得Vue具备了现代框架应有的高级特性。 三、Vue3.0对Virtual DOM的优化

Vdom凭借着出色的性能成为了目前主流的前端框架都会选择的渲染方案。再加上优秀的 diff算法 对它的一步步的优化,使框架的价值得到了极致的体现,成为了我们前端框架必不可少的方案。 Vue2.x中的Vdom已经相当出色了,性能非常优秀。但在Vue3中还是对Vdom进行了重写,使Vue3突破了Vdom的性能瓶颈,贼拉快!

1.初试牛刀:

我们在Vue Template Explorer 上做测试可以更直观的看到Vnode的样子。

当我们创建一个静态 dom 元素的时候: Hello World! Vue3编译后的Vdom长这个样子的: export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("span", null, "Hello World!")) }

看似比较复杂,实际上 _createElementBlock 函数中才是我们创建的 dom,从它身上我们可以看出,我们创建了一个 span 元素,内容为 “Hello World!”。这就是 Vdom 最基础的形式,在这里我们并不会感觉到Vue3与Vue2有什么区别。

2.patch flag 优化静态树 我们现在换一下,当我们创建一个动态的dom元素时: Hello World! Good Morning! {{name}} Vue3编译后的Vdom长这个样子的: export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock(_Fragment, null, [ _createElementVNode("span", null, "Hello World!"), _createElementVNode("span", null, "Good Morning!"), _createElementVNode("span", null, _toDisplayString(_ctx.name), 1 /* TEXT */) ], 64 /* STABLE_FRAGMENT */)) } // 如果是动态绑定的val在渲染dom的时候会在 _createElementVNode函数后面追加动态标记1

创建动态 dom 元素的时候,Vdom 除了模拟出dom基本信息之外,还加了一个:1 /* TEXT */,这个值1便是标记。

这个标记就叫做 patch flag(补丁标记)

patch flag 的强大之处在于,当你的 diff 算法走到 _createElementBlock 函数的时候,会忽略所有的静态节点,只对有标记的动态节点进行对比,而且在多层的嵌套下依然有效。Vue2.x 中,重复渲染时静态不变化的内容依旧会重建 Vdom,diff 时仍需对比。

newold.png

尽管JavaScript做 Vdom 的对比已经非常的快,但是 patch flag 的出现还是让 Vue3 的 Vdom 的性能得到了很大的提升,尤其是在针对比较复杂的大组件时。经过测试的 upadte 性能提升1.3到2倍,ssr 提升2到3倍

3.patch flag 优化静态属性 1.静态绑定 当我们创建一个有属性的元素: {{msg}} Vue3编译后的Vdom是这个样子的: export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("span", { id: "hello" }, _toDisplayString(_ctx.msg), 1 /* TEXT */)) }

让我们观察它的 patch flag,发现并没有对id做特殊的标记。是因为dom元素的静态属性在渲染的时候就已经创建了,并且是不会变动的,在后面进行更新的时候,diff 算法是不会去管它的。

2.动态绑定 当我们创建一个属性是动态绑定的元素: {{msg}} Vue3编译后的Vdom是这个样子的: export function render(_ctx, _cache, $props, $setup, $data, $options) { return (_openBlock(), _createElementBlock("span", { id: _ctx.hello }, _toDisplayString(_ctx.msg), 9 /* TEXT, PROPS */, ["id"])) }

再观察它的 patch flag,会发现变成了 9 /* TEXT, PROPS */, 而且后边还多了一个数组 ["id"]

静态标记中注释的内容,很明显的告诉我们,这个元素不止TEXT变化,它的属性PROPS也会变化。后边的数组内容则是有可能变化的属性

原来,Vue3 在 Vdom 的更新时,只会关注它有变化的部分。这样的优化使 Vue3 既跳出了 Vdom 的性能瓶颈,又依然保留了可以手写 render function 的灵活性。相当于 Vue3 既有 React 的灵活性,又有基于模板的性能保证。————尤雨溪

附上静态标记值的一份注释,里面使用了位运算:

export const enum PatchFlags { TEXT = 1,// 1 表示具有动态textContent的元素 CLASS = 1


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3