这是我参与2022首次更文挑战的第2天,活动详情查看:2022首次更文挑战
vue3的效率比vue2有了很大的提升。客户端渲染效率比vue2提升了1.3-2倍,SSR渲染效率比vue2提升了2-3倍。那么vue3的效率提升主要表现在哪些方面呢?
静态提升
静态提升是什么意思呢?vue里面有编译器,它能够把模板编译成render函数。
编译器会发现静态节点,把它进行提升。
下面静态节点会进行提升
- 元素节点
- 没有绑定动态内容 我们看一下下面的例子,看一下vue2和vue3的对比
<h1>Hello World</h1>
// vue2的静态节点
render(){
createVNode("h1",null,"Hello World")
// ...
}
// vue3的静态节点
const hoisted = createVNode("h1",null,"Hello World")
function render(){
// 直接使用hoisted即可
}
我们可以发现,vue2是直接在render函数里面创建一个虚拟节点,vue3则是把创建虚拟节点给提到上面去了,不在render函数里面创建。这样子一来,这个节点就只创建一次,之后在render函数里面重复使用就好了。
静态属性也会被提升
<div class="user">
{{user.name}}
</div>
const hoisted = { class:"user" }
function render(){
createVNode("div",hoisted,user.name)
// ...
}
我们可以发现,尽管上面节点不是静态的,但它的属性是静态的,我们可以把属性对象给提出来,可以在render函数里重复使用,减少内存占用。
预字符串化
平时我们开发组件时会发现好多元素都是静态元素,只有少量的元素是动态的。也就是动静比较小。
<div class="menu-bar-container">
<div class="logo">
<h1>logo</h1>
</div>
<ul class="nav">
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
<li><a href="">menu</a></li>
</ul>
<div class="user">
<span>{{ user.name }}</span>
</div>
</div>
当编译器遇到大量连续的静态内容,会直接将其编译为一个普通字符串节点
const _hoisted_2 = _createStaticVNode("<div class=\"logo\"><h1>logo</h1></div><ul class=\"nav\"><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li><li><a href=\"\">menu</a></li></ul>")
vue3虚拟节点树
缓存事件处理函数
我们看一下下面的例子
<button @click="count++">plus</button>
// vue2
render(ctx){
return createVNode("button",{
onClick: function($event){
ctx.count++;
}
})
}
// vue3
render(ctx,_cache){
return createVNode("button",{
onClick: cache[0] || (cache[0] = ($event) => (ctx.count++))
})
}
vue2里面编译是先编译一个节点,名字是button,然后它的属性里面多了一个事件onClick,它有个函数,函数里面就是count++。这是vue2的处理方式。
vue3处理方式是有了缓存。vue3的渲染函数里面有个参数cache,在写onClick的时候编译成一个函数,它会看一下缓存对象里面有没有这个函数,有的话就直接返回,没有的话就给这一项赋值,赋值为函数,这个函数就是count++。它能保证事件处理函数只生成一次,下一次就不用生成了。
Block Tree
vue2在对比新旧树的时候,并不知道哪些节点是静态的,哪些是动态的,因此只能一层一层比较,这就浪费了大部分时间在对比静态节点上。
vue3可以依托它强大的编译器,编译器能够标记每一个节点是动态节点还是静态节点,而且它会把动态节点给记录下来给提取到根节点里面去。这样子有什么好处呢? 到时候对比的时候它不是整颗树做对比,而是直接找到根节点,找到记录动态节点的数组,循环数组,进行对比。这样子就不涉及树的深度遍历和广度遍历,也跳过了静态节点。
PatchFlag
vue2在对比每一个节点时,并不知道这个节点哪些相关信息会发生变化,因此只能将所有信息依次对比。
<div class="user" data-id="1" title="user name">
{{ user.name }}
</div>
patchflag是记录标识一个节点如何更新的。它能使vue3对比每一个节点的时候效率进一步提升了。
以上就是vue3的效率的提升所做的优化。