对比Vue2和React,Vue3的渲染效率简直不要太快。在分析的时候不仅是读懂相关的代码,更要从设计的角度中得到启发。
模板提升、缓存
Vue3的模板引擎会将我们写的模板编译成为一个render函数,而在编译的时候会进行预编译。编译器会发现静态节点,并将节点进行提升。
vue模板
<div>Hello World</div>
<div class='user'>{{name}}</div>
经过模板引擎编译后
const _hoisted_1 = _createVNode('div',null,'Hello World')
const _hoisted_2 = {class:'user'}
functoin render(){
// 直接读取_hoisted_1
// _createVNode('div', hoisted_2, name)
//...
}
当组件里面有大量的静态节点,动静比大时
<div>
<p>fruit</p>
<ul>
<li>apple</li>
<li>banner</li>
<li>orange</li>
<li>watermelon</li>
<li>pear</li>
</ul>
<span>{{else}}</span>
</div>
编译后
const _hoisted = _createStaticVNode("<p>fruit</p><ul<li>apple</li><li>banner</li><li>orange</li><li>watermelon</li><li>pear</li></ul>")
当节点中存在事件函数时
<button @click='count++'>add</button>
因为事件函数不会在编译时有变更,可以将事件函数进行缓存,
render(ctx, _cache){
return _createVNode('button',{
//保证事件函数只生成一次
onClick: cache[0] || (cache[0] = ($event) => (ctx.count++))
})
}
block tree
vue2在对比新旧虚拟Dom的时候是将每个节点一一对比是十分浪费性能的。
vue3则是依托于强大的编译器,会在节点上标记为动态节点或静态节点。根节点会生成一个数组记录所有的动态节点。对比的时候直接找到根节点,也就是block节点。在对比的时候只需要循环数组,就会跳过静态节点,直接对比动态节点。
在进行单个节点对比的时候,由于编译器将模板中的动态属性都有标记,比对效率大大的提升。