静态提升
相比vue2,vue3对以下静态节点进行提升:
- 元素节点
- 没有绑定的动态内容
render(h){
h('h1',null,'this is h1')
}
const hoisted = createdVNode('h1',null,'this is h1')
render(){
}
通过打开vue3工程,可以看到起运行代码中包含着hoisted标记的变量,/*@__PURE__*/则告诉打包工具该函数是非dead code代码,如图: 同时我们通过测试也可以发现,vue3里手写vnode可以缩小到如下三个属性,测试发现缺少shapeFlag并不能生效。
render() {
return {
"type": "h1",
"children": "this is h1",
"shapeFlag": 9,
}
}
vue2的vnode和vue3有所区别,主要是某些属性的表述上有所差异,具体用法其实是一样的。
除了静态节点的提升,静态属性也是可以被提升的。
<div class="user">
{{user.name}}
</div>
const hoisted = {
class:'user'
}
function render(){
createVNode('div',hoisted,user.name)
}
预字符串化
实际开发中,一个组件实际上大多数东西是静态的,只有少数东西是使用变量。
<template>
<div>
<div>1</div>
<div>2</div>
<div>3</div>
<div>4</div>
</div>
<div>{{ list }}</div>
</template>
vue2对于模板的处理是解析器parseHTML,通过标记和不断循环生成一个带有type、tag、attrsList、children等属性的对象,所以生成的vnode实际上是一棵包含了静态和动态的巨大树。
vue3对于静态节点会处理成字符串,该优化在ssr下的性能提升尤为明显。值得注意的是,目前vue3只会对连续的静态节点才会预字符串化,经过测试目前版本3.2.31当连续静态标签为5个时可以触发预字符串化。
<template>
<div class="user">
<ul>
<li @click="msg++">add</li>
<li>{{ msg }}</li>
<div>sogo</div>
<li>hhhh</li>
<li>hhhh</li>
<li>
<ul>
<li>hhhh</li>
<li>hhhh</li>
<li>hhhh</li>
<li>hhhh</li>
<li>hhhh</li>
</ul>
</li>
<div><div>333</div></div>
<li>{{ msg }}</li>
</ul>
</div>
</template>
缓存事件处理函数
vue3认为事件的处理一般是不会变化的,所以其对事件处理函数进行缓存。
render(ctx){
return createVNode('button',{
onClick:function($event){
ctx.count++
}
})
}
render(ctx,_cache){
return createVNode('button',{
onClick:cache[0] || (cache[0] = ($event) => ctx.count++)
})
}
从图中的vue3工程可以看到click事件引入缓存处理。
Block Tree
在vue2中,新旧树对比,很多时候会对新旧两颗树的相同静态节点进行多次对比。vue3优化了这一处理,其会在block tree的根节点记录该树的动态节点,直接跳过静态节点的对比。所以该处理不用深度遍历和广度遍历,在静态节点更多的情况下,其性能远远领先vue2的diff。
需要注意的是,该处理是基于树稳定的情况下,当该树的某一节点不稳定时,会将其拆为另一个block tree。
PatchFlag
vue2在新旧树对比时,需要对比属性是否变化,内容是否变化等,而vue3会通过patchFlag标记这些节点类型、节点属性、节点内容等,在新旧树对比中只对比某一属性。
|