Vue 3.0到底怎么变快?🚀

1,878 阅读4分钟

前言🖖

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

Vue 3.0亮点🤩

  • Vue 3.0性能比Vue 2.x1.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操作,而不用重新渲染整个页面。

image.png

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

Vue 2.x

image.png

Vue 3.0

image.png

  • 从上面的图例可知在Vue 2.xdiff算法会将两棵DOM树的所有节点进行对比,但实际变化的只有双向绑定的那个。
  • Vue 3.0中会在创建虚拟DOM的时候将会变化的内容进行静态标记,这样diff算法的时候直接对比有标记的,对比的少了自然而然速度就变快了。 在Vue 3 Template Explorer中显示如下 image.png 上面flag的1是Patchflag枚举,取值为1代表这个元素的文本是动态绑定的
附录:PatchFlags
export const enum PatchFlags {Ⅰ
		TEXT = 1,1/动态文本节点
		CLASS = 1<<11/ 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>

未使用静态提升

image.png 使用静态提升

image.png

  • 从上面的两幅对比图可以明显的看到未使用静态提升的变量会放在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>

未使用事件侦听器缓存

image.png 使用事件侦听器缓存

image.png

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

写在最后👌

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

参考👈