Vue3.0亮点
- Vue 3.0性能比Vue 2.x快 1.2~2倍
- 新推出的Composition API 使组件更易维护
- 更好TypeScript支持
- Custom Render API:暴露了自定义渲染API
Vue3.0到底是如何变快
diff算法优化
- 熟悉Vue 2.x的兄弟都知道渲染真实DOM的开销是很大的,比如我们修改某个数据直接渲染在真实DOM上会引起DOM树的重排重绘。
- 于是就有了diff算法可以根据真实DOM生成一棵虚拟DOM树(Virtual DOM)从而计算出 Virtual DOM 中被改变的部分,然后针对该部分进行原生DOM操作,而不用重新渲染整个页面。
- 值得注意的是diff算法是对树的每一层进行遍历从而找出不同进行替换(图片来自网络),而Vue3.0的diff算法就在此做出了优化。
- 举个例子说明一下吧,在下面有两个p标签一个是不会变的数据一个是绑定的数据,当sth改变的时候,Vue会生成新的虚拟DOM然后和旧的进行对比。
<div>
<p>hi 小卢!!</p>
<p>{{sth}}</p>
</div>
在Vue 2.x中
在Vue 3.0中
- 从上面的图例可知在Vue 2.x中diff算法会将两棵DOM树的所有节点进行对比,但实际变化的只有双向绑定的那个。
- Vue 3.0中会在创建虚拟DOM的时候将会变化的内容进行静态标记,这样diff算法的时候直接对比有标记的,对比的少了自然而然速度就变快了。
在Vue 3 Template Explorer中显示如下
上面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>
未使用静态提升
使用静态提升
- 从上面的两幅对比图可以明显的看到未使用静态提升的变量会放在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>
未使用事件侦听器缓存
使用事件侦听器缓存
上面转换过的代码如果看不懂的话没有关系,我们只需要观察它是否有静态标记即可。
从上面两幅对比图可以看出来在使用了事件监听器缓存的情况下它的静态标记8消失了,就说明在Vue 3.0在每次数据更新时不会对它进行对比了,对比的少了自然而然速度也就加快了