vue3-vue3的高效

270 阅读4分钟

概述:尤大大说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在对比新旧数的时候,并不知道哪些节点是静态的,哪些是动态的。因此只能一层一层比较,这就浪费了大部分时间在对比静态节点上。

image.png 生成了这个一棵树,在patch的时候,是挨个进行对比的。这是静态节点,没有变化了,所以这就做了很多无意义的对比。

vue3的编译器就很强大了,对每个节点进行标记,到底是静态的还是动态的。

image.png 编译器会把所有的动态节点提取到根节点form里。form节点里有一个数组,记录了后代节点中哪些是动态的。那么在对比的时候,不是整棵树进行对比,而是直接找到根节点,也就是block节点。就是说哪个节点记录了哪些是动态节点,那那个节点就是block节点。这时候进行对比,也就是循环数组进行对比,只对动态节点进行对比,越过了静态节点。

当然树会有不稳定的时候,不稳定的那个分支会自动变成一个block

5.patchFlag

这个已经是达到变态的级别了。

vue2在对比某个节点时,并不知道这个节点哪些相关信息会发生变化,因此只能将所有信息依次比对。

vuu3觉得在对比某个节点的时候还是在浪费效率,尽管是跳过了所有的静态节点。那在对单个节点对比的时候,就通过这个patchFlag来进行了优化。它会记录这个节点的属性,样式等信息是不是动态的。有了这个记录,那下次更新的时候,如果属性样式都是静态,那就只比较动态的内容。