概述:尤大大说
vue3的效率相比vue2有很大的提升,那提升的点在哪里,是如何提升的?可以总结起来,有四个方面:a.静态提升 b.预字符串化 c.缓存事件处理函数 d.Block Tree e.PatchFlag。
1.静态提升
vue里有个包用来处理单文件组件的,所以有个预编译过程啊,它会把模版编译成render函数,它的编译现在很智能,能发现哪些是静态节点,哪些是动态节点,然后把静态节点进行提升。
ps: 静态节点:一个没有绑定动态属性的节点。
怎么提升呢?
在vue2里就是这么创建一个静态节点。
//vue2的静态节点
render(){
createVNode('h1', null, 'Hello World');
}
在vue3里,他觉得既然是静态节点,那就不可能变化,所以不在render函数里创建。因为render函数是会不断执行的,所以静态节点就没必要每次都创建。那么这样一来,这个静态节点就只创建一次。
const hoisted = createVNode("h1", null, "hello word");
function render() {
//直接使用
}
这就是静态节点的提升。还有静态属性也会被提升。
<h1 class="title">{{ msg }}</h1>
这种情况下是动态节点了,但class属性是静态的,那就可以提升。
const hoisted = { class: "title" };
function render() {
createVNode("h1", hoisted, msg);
}
动态节点放到render里创建了,但是静态属性放外面了,这样每次创建节点的时候就可以复用静态属性了。
2.预字符串化
这个点是超级超级厉害的的,就跟十倍界王拳一样😎。
单文件组件的模板里,回想一下,其实在大多文件里,静态节点是比动态节点还要多的。vue3的编译器很智能的发现这一点,发现了我们使用了大量连续的静态元素,他就把我们这段静态元素编译成一串字符串了,是大量的连续的静态节点,目前是20个。
const _hoisted = _createStaticVNode( `<div class=\"box\"><ul><li>1</li><li>1</li><li>1</li><li>1</li></ul></div>`;)
但是vue2是把这些节点都创建为虚拟节点。
所以这么一处理,vue3的节点数就变少了,这一点在ssr里作用非常明显,服务端将节点进行预字符串过后,只是不断的往客户端发送字符串,客户端做个字符串拼接就完事了。
3.缓存事件处理函数
这个点是更是厉害的😎。
比如说有个按钮有点击事件。
<button @click="Count++">Plus</button>
在vue2里这么处理的:
render(ctx){
return createVNode('button',{
onclick: function($event){
ctx.count++
}
})
}
那vue3的处理就有缓存了,它认为渲染的时候这个函数是不会发生变化。
render(ctx,_ceche){
return createVNode('button',{
onclick: ceche[0]||(ceche[0] = ($event) => (ctx.count++))
})
}
多了一个缓存对象,在写onclick的时候,会把count++编译成一个函数,看一下缓存对象里有没有这个函数,有的话直接返回,没有的话就给这一项赋值。
4.Block Tree
这个也是个很大的更新,是自动完成的,非常的强大,直接是变赛亚人了那种。那它是为了解决什么问题呢?是为了提高新旧两棵树在对比时的效率。
比如有这么一个模板。
<form>
<div>
<label>账号</label>
<input type="text" v-model="user.loginId" />
</div>
<div>
<label>密码</label>
<input type="text" v-model="user.loginPwd" />
</div>
</form>
vue2在对比新旧数的时候,并不知道哪些节点是静态的,哪些是动态的。因此只能一层一层比较,这就浪费了大部分时间在对比静态节点上。
生成了这个一棵树,在
patch的时候,是挨个进行对比的。这是静态节点,没有变化了,所以这就做了很多无意义的对比。
vue3的编译器就很强大了,对每个节点进行标记,到底是静态的还是动态的。
编译器会把所有的动态节点提取到根节点
form里。form节点里有一个数组,记录了后代节点中哪些是动态的。那么在对比的时候,不是整棵树进行对比,而是直接找到根节点,也就是block节点。就是说哪个节点记录了哪些是动态节点,那那个节点就是block节点。这时候进行对比,也就是循环数组进行对比,只对动态节点进行对比,越过了静态节点。
当然树会有不稳定的时候,不稳定的那个分支会自动变成一个block。
5.patchFlag
这个已经是达到变态的级别了。
vue2在对比某个节点时,并不知道这个节点哪些相关信息会发生变化,因此只能将所有信息依次比对。
vuu3觉得在对比某个节点的时候还是在浪费效率,尽管是跳过了所有的静态节点。那在对单个节点对比的时候,就通过这个patchFlag来进行了优化。它会记录这个节点的属性,样式等信息是不是动态的。有了这个记录,那下次更新的时候,如果属性样式都是静态,那就只比较动态的内容。