vue3对vdom进行了重写,使vue3突破了vdom的性能瓶颈,更快!
推荐:vue3官方演示vdom的示例网站(https://vue-next-template-explorer.netlify.app)
Vue3如何重写vdom
⭐️入门
- 当我们创建一个这样的静态 dom 元素的时候:
- vue3生成的vdom是这样的
实际上 _createBlock 函数中才是我们创建的 dom,这是vdom最基础的形式,从这并不会感觉到vue2和vue3有什么不同。
⭐️patch flag 优化静态树
- 当我们创建了一个动态的dom元素
- vue3生成的vdom是这样的
我们发现创建动态 dom 元素的时候,Vdom 除了模拟出来了它的基本信息之外,还给它加了一个标记: 1 /* TEXT */,这个标记就叫做 patch flag
patch flag的强大之处在于,当你的 diff 算法走到 _createBlock 函数的时候,会忽略所有的静态节点,只对有标记的动态节点进行对比,而且在多层的嵌套下依然有效。
尽管 JavaScript 做 Vdom 的对比已经非常的快,但是标记的出现还是让 Vue3 的 Vdom 的性能得到了很大的提升,尤其是在针对大组件的时候。
⭐️patch flag 优化静态属性
- 当我们创建一个有静态属性的元素:
- vue3编译后的vdom是这样的:
让我们观察它的 patch flag ,发现并没有对 id 做特殊的标记。是因为 dom 元素的静态属性在渲染的时候就已经创建了,并且是不会变动的,在后面进行更新的时候,diff 算法是不会去管它的。
⭐️动态绑定属性
- 当我们创建一个属性是动态绑定的元素
- vue3编译后的vdom是这样的
再观察它的 patch flag ,会发现变成了 9 /* TEXT, PROPS */,而且后边多了一个数组 [“id”]
这里的 patch flag 中的注释的内容告诉我们,这一个 dom 元素不止有内容 TEXT 会变化,它的属性 PROPS 也会变化。而后边的数组中的内容则是有可能发生变化的属性。
看到这里,我们就会明白 Vue3 实际做的事情了。
Vue3 在 Vdom 的更新时,只会关注它有变化的部分。这样的优化使 Vue3 既跳出了 Vdom 的性能瓶颈,又依然保留了可以手写 render function 的灵活性。相当于 Vue3 既有 react 的灵活性,又有基于模板的性能保证。——尤雨溪
⭐️patch flag 静态提升
刚刚我们提到 Vue3 突破 Vdom 的性能瓶颈的方式是,只关注它有变化的部分。而在更新时具体是怎么做的呢?
具体的做法就是 静态树的提升 和 静态属性的提升
-
我们创建若干的 dom 元素:
-
静态提升之后:
我们已经知道处理后的 Vdom 都在 _createBlock 函数之中,而观察结果我们发现,所有的静态元素都被放在了 _createBlock 函数之外了,也就是说他们只会在页面初始的时候被渲染一次,而在更新的时候,静态元素是不予搭理的。
这个优化就是 Vue3 的 静态提升
⭐️事件侦听器缓存
- 建一个带有事件侦听的元素
- 没有进行事件侦听器缓存的 Vdom
在这里的 _createBlock 函数中就是这个元素的 Vdom 结构。观察高亮的地方,发现 onClick 函数以变量的形式存在。 - 进行事件侦听器缓存后的 Vdom
观察高亮的那一行,我们发现 onClick 函数的储存位置变成了缓存的形式。也就是说 当你的页面在不断的更新的时候,你的事件侦听器并不会重复地销毁再创建,而是以缓存的形式存在,这使 Vue3 在性能方面又有了一个出彩的地方。
另外,Vue3 在 @click 中,直接手写内联函数也会被缓存起来,这一点是 react 做不到的。再加上 在 Vue3 中父组件的更新并不会直接触发子组件的更新,使得事件侦听器缓存在组件的层面可以提现出来更高的价值。