本文根据Vue.js作者尤雨溪的演讲实录,结合自己的理解整理而成:

一、Vue3.0会带来什么?

我们的目标是让Vue:
1、更快
2、更小
3、更易于维护
4、更好的多端渲染支持
5、新功能API

同时尽量保证代码的兼容,当然不可避免会带来代码上的改动,但是会尽量把这些改动保持在最小。因为能够让更多的用户平滑的从2.0升级到3.0是我们最重要的一个目标。

如何更快

1、新的Virtual DOM完全重构

初始渲染/更新提速达到100%

首先我们来聊一聊,怎么让Vue变得更快。

大家都知道Vue用的是Virtual DOM内部渲染机制,在3.0对Virtual DOM进行了一次完全的重构,在很多细节的地方下了很多功夫,深度挖掘性能提升。

同时也有一些结合模板编译来提供运行时性能的一些小技巧。总体来说,当从这个重构的表现来看,我们在大部分情况下,初始渲染更新的提速最高可以翻倍!

2、更多编译时的优化,以减小运行时开销

我们知道Virtual DOM这个概念,其实它在运行时有很多的潜在性能开销的,比如说在模板里面,我们其实有很多不会变动的地方,但是Virtual DOM不可避免要重新生成对应的节点,对它们进行比对。

这些操作在很多情况下其实并不必要,我们可以通过在编译时对我们的模板进行分析来减少这些运行时的开销。在目前的Vue2.x里面,已经有一些类似的一定程度的优化,但是做的还不够彻底。3.0里面希望更近一步,尽可能通过编译时的分析,来压榨更多的性能。

我们下面要举出一些具体的例子,首先一个简单的例子就是:当我们将模板编译为Virtual DOM的渲染函数的时候,vue2.0的行为是不管是html原生标签还是原生组件,都是作为字符串传到h函数里。

然后我们通过判断一个元素到底是组件还是原生标签的时候,这个过程是在运行时来做的,这里就不可避免 每个元素都要检查一遍它是原生,还是可能是个组件,这里面就会有一定的运行时开销。实际上这个开销,我们可以通过在编译时来判断,如果它是一个原生html标签的话,在运行时直接生成对应的Virtual DOM的代码;同样的我们知道它是组件的话,就直接生成对应组件的Virtual DOM代码。

这就是所谓的Componment Fast Path!

还有一个就是在生成函数的时候,要尽可能的函数形状一致,也就是有同样个数的参数。这样的话,会使得我们生成代码,更易于被JS引擎去优化。这种就是属于比较底层的优化技巧。

最后一个我们可以做的就是在模板中直接静态的分析一个元素所包含的子元素的类型,根据子节点的个数,在生成的代码里面给运行时留下一些提示,直接留下一个数字,告诉说这个div 它现在只有一个子元素,那么在代码的算法分支里面就可以直接跳入只有一个子元素的分支, 从而可以跳过很多比必要的判断。

这样的优化积少成多,就可以在整个应用中得到相当可观的收益

3、优化slot生成

举例说明,当你把一个slot内容传到一个子组件里的时候,每一次hello发生变化, 其实我们首先更新父组件,同时生成新的slot内容传递给子组件, 然后子组件也会更新,这就是父子关联更新。

也就是说我们为了更新一块内容,其实触发了两个组件的更新。

在新的渲染机制里面,我们把所有的slot统一生成为一个函数,它是一个lazy的函数。

当你把函数传给子组件之后, 由子组件来决定什么时候来调用这个函数。当子组件调用函数的时候,这个slot里面的依赖就会变成子组件的依赖,而不是父组件的。 这样我们就只需要重新渲染子组件,父组件与子组件的依赖彻底分开了

最终我们在整个应用中,我们就会得到一个非常精确的组件级的依赖收集,进一步的避免不必要的组件渲染。这一点解决之后,vue 组件的更新监测基本可以说得上是完全精确的。也就是说任何时候,只有真正依赖了某个数据的组件,才可能重新渲染。 这样就存在需要手动优化组件过度渲染重绘的问题。

4、静态内容提取

静态模板提取在vue2.x中已经做了,也就是我们检测到一部分模板是不变的,直接可以提取出来,那么在更新中,这一部分模板不仅可以直接复用之前的Virtual DOM,而不用参与dom diff的这个过程

vue2.x中没有做的一点就是,当一个元素内部包含任意深度,包含任意动态内容的时候,整个元素是无法被静态化。

这就是很可惜,但是我们其实是可以做一定程度的优化。