前言????

自从​​Vue3.0​​发布后一直想要学习一下新特性,谁曾想到一直鸽到了现在。面对前端行业不学习就被淘汰的内卷环境什么都要学起来呀,学的时候索性记录总结一下。

Vue 3.0亮点????

  • ​Vue 3.0​​​性能比​​Vue 2.x​​快1.2~2
  • ​Tree-Shaking​​​:按需编译,体积比​​Vue 2.x​
  • 新推出的​​Composition API​​ 使组件更易维护
  • 更好​​TypeScript​支持
  • ​Custom Render API​​​:暴露了自定义渲染​​API​
  • 更多先进牛逼的组件


总的来说就是更快更小更舒服


Vue 3.0到底是如何变快????

大家都说​​Vue 3.0​​变快了,那他到底是哪里快了呢?做了哪些优化才会让它有这种效果?

diff算法优化????

  • 熟悉​​Vue 2.x​​的兄弟都知道渲染真实​​DOM​​的开销是很大的,比如我们修改某个数据直接渲染在真实​​DOM​​上会引起​​DOM​​树的重排重绘。
  • 于是就有了​​diff​​算法可以根据真实​​DOM​​生成一棵虚拟​​DOM​​树(​​Virtual DOM​​)从而计算出 ​​Virtual DOM​​ 中被改变的部分,然后针对该部分进行原生​​DOM​​操作,而不用重新渲染整个页面。

Vue 3.0到底怎么变快?_缓存

  • 值得注意的是​​diff​​算法是对树的每一层进行遍历从而找出不同进行替换(图片来自网络),而​​Vue3.0​​​的​​diff​​算法就在此做出了优化。
  • 举个例子说明一下吧,在下面有两个​​p​​​标签一个是不会变的数据一个是绑定的数据,当​​sth​​​改变的时候,​​Vue​​​会生成新的虚拟​​DOM​​然后和旧的进行对比。
<div>
<p>hi 小卢!!</p>
<p>{{sth}}</p>
</div>

Vue 2.x

Vue 3.0到底怎么变快?_缓存_02

Vue 3.0

Vue 3.0到底怎么变快?_前端_03

  • 从上面的图例可知在​​Vue 2.x​​​中​​diff​​​算法会将两棵​​DOM​​树的所有节点进行对比,但实际变化的只有双向绑定的那个。
  • 在​​Vue 3.0​​​中会在创建虚拟​​DOM​​的时候将会变化的内容进行静态标记,这样​​diff​​算法的时候直接对比有标记的,对比的少了自然而然速度就变快了。

在​​Vue 3 Template Explorer​​​中显示如下 Vue 3.0到底怎么变快?_子节点_04上面flag的1是​Patchflag​枚举,取值为1代表这个元素的文本是动态绑定的

附录:PatchFlags
export const enum PatchFlags {Ⅰ
TEXT = 1,1/动态文本节点
CLASS = 1<<1,1/ 2// 动态 classSTYLE= 1<<2,// 4//动态 style
PROPS = 1<< 3,// 8// 动态属性,但不包含类名和样式
FULL_PROPS = 1<<4,// 16 //具有动态 key属性,当key改变时,需要进行完整的 diff 比较。
HYDRATE_EVENTS = 1<<5,// 32//带有监听事件的节点
STABLE_FRAGMENT = 1<<6,// 64//一个不会改变子节点顺序的 fragment
KEYED_FRAGMENT = 1<<7,// 128//带有key属性的 fragment 或部分子字节有
keyUNKEYED_FRAGMENT = 1<<8,// 256//子节点没有key 的 fragment
NEED_ PATCH =1<<9,//512//一个节点只会进行非 props比较
DYNAMIC_SLOTS = 1 << 10,//1024 // 动态的插槽

// SPECIAL FLAGS (下面是特殊的)---------------------------------------------------------
// 以下是特殊的flag,不会在优化中被用到,是内置的特殊flag
// 表示他是静态节点,他的内容永远不会改变,对于hydrate的过程中,不会需要再对其子节点进行diff
HOISTED = -1,
BAIL = -2, // 用来表示一个节点的diff应该结束
}

如果想更多了解PatchFlags可以阅读​Vue3的patchFlags超详细讲解​

hoistStatic(静态提升)????

  • 这就好比你每天去便利店买咖啡,每次买的时候店员都问你需要什么,当时间久了店员熟悉了你的习惯就省去了店员问你'要什么'的这个过程,直接给你所需要的商品。
  • 顾名思义​​静态提升​​​就是把不参与更新的静态元素给提升出来,说白了就是类似把变量变成常量​​不进行重新创建​​。
  • 在​​Vue 2.x​​中无论元素是否参与更新每次都会重新创建,然后渲染,这对于性能肯定是会有些许损耗。

举个例子说明一下

<div>
<div>Hello Vue3.0</div>
<div>hi 小卢!</div>
<p>{{sth}}</p>
</div>

​未使用静态提升​

Vue 3.0到底怎么变快?_Vue.js_05 ​​​使用静态提升​

Vue 3.0到底怎么变快?_Vue.js_06

  • 从上面的两幅对比图可以明显的看到​​未使用静态提升​​​的变量会放在​​render​​函数里面,每次更新数据都会重新创建并渲染出来
  • 而​​使用了静态提升​​​的元素会被提取出来放在​​render​​函数外面,这样下次更新的时候就不会把这个元素重新创建,创建的元素少了,自然而然速度也就起来了。
  • ​Vue 3.0​​​中就是​​启用了静态提升​​把不需要更新的元素放到外面只创建一次,在渲染的时候直接复用即可。

cacheHandlers(事件侦听器缓存)????

  • 从上面的​​diff​​​算法优化中我们知道,根据​​PatchFlags​​会把动态绑定的元素加上静态标记,那一个事件函数自然就会被加上静态标记,在​​diff​​中会将有标记的元素进行对比来更新数据。
  • 如果我们用的这个函数从头到尾都没有改变过,那是不是也可以让它像静态元素一样不进行对比呢?
  • 那我都这么问了答案肯定是:可以的!
  • 顾名思义事件侦听器缓存就是把没有改变过的事件给侦听到了,然后缓存。
  • 就好比刚学​​Vue​​​的你不懂各种​​api​​​和优秀的组件,每次用到的时候都会去查看看怎么做,但是当你做久了之后自然你就熟能生巧了,没有得到消息说​​api​​更新了,自然就不会去查找文档对比有什么差异。

举个例子说明一下

<div>
<div>Hello Vue3.0</div>
<div>hi 小卢!</div>
<p>{{sth}}</p>
<div @click="doSthing">我是一个点击事件</div>
</div>

​未使用事件侦听器缓存​

Vue 3.0到底怎么变快?_Vue.js_07 ​​​使用事件侦听器缓存​

Vue 3.0到底怎么变快?_缓存_08

  • 上面转换过的代码如果看不懂的话没有关系,我们只需要观察它是否有静态标记即可。
  • 从上面两幅对比图可以看出来在使用了事件监听器缓存的情况下它的静态标记​​8​​​消失了,就说明在​​Vue 3.0​​在每次数据更新时不会对它进行对比了,对比的少了自然而然速度也就加快

写在最后????

  • 以上就是​​Vue 3.0​​变快做的一些优化。
  • 总的来说​​Vue 3.0​​​通过优化​​diff​​算法让该对比的进行对比,不该对比的不进行对比。
  • 通过静态提升事件侦听缓存来减少不变的元素创建的频率,​​加快了​​运行速度。
  • 如果您觉得这篇文章有帮助到您的的话不妨点赞支持一下哟~~????

参考????