响应式系统升级
首先来看一下响应式系统升级。我们都知道Vue2的时候,数据响应式的原理使用的是
defineProperty
,在初始化的时候会遍历data
中的所有成员。通过defineProperty
,把对象的属性转换成getter
和setter
。如果data
中的属性又是对象的话,需要递归处理每一个子对象的属性。注意这些都是在初始化的时候进行的。也就是说如果你没有使用这个属性的时候,你也把它进行了响应式的处理。而Vue3中采用的是
ES6
以后新增的proxy
对象。proxy
对象的性能本身就比defineProperty
要好。另外,代理对象可以拦截属性的访问、复制、删除等操作。不需要初始化的时候遍历所有的属性。另外,如果有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性,使用proxy
对象默认就可以监听到动态添加的属性。而Vue2里边想要动态添加一个显示的属性需要调用this.$set
的方法来处理。而且Vue2中还监听不到属性的删除,对数组的索引和length属性的修改也监听不到。Vue3中使用代理对象可以监听属性的删除以及数组的索引和length属性的修改操作。所以Vue3中使用proxy
对象提升了响应式系统的性能和功能。
编译优化
Vue3中通过优化编译的过程和重写虚拟
DOM
,让首次渲染和更新的性能有了大幅度的提升。我们知道Vue2的时候,模板首先需要编译成render
函数,这个过程一般是在构建的过程中完成的。在编译的时候会编译静态根节点和静态节点。静态根节点要求节点中必须有一个静态子节点,当组件的状态发生变化后,会通知watch
触发watcher
和update
。最终去执行虚拟DOM
的patch
操作遍历所有的虚拟节点,找到差异,然后更新到真实DOM
上。
Diff
的过程中会去比较整个虚拟DOM
,先对比新旧的div
以及它的属性,然后再对比它内部的子节点。Vue2中渲染的最小单位是组件。Vue2中diff
的过程会跳过静态根节点,因为静态根节点的内容不会发生变化,也就是Vue2中通过标记静态根节点优化了diff
的过程。但是在Vue2的时候,静态节点还需要再进行diff
,这个过程没有被优化。Vue3中为了提高性能,在编译的时候会标记和提升所有的静态节点,然后
diff
的时候只需要对比动态节点的内容。另外在Vue3中新引入了一个Fragments
,也就是片段的特性,模板中不需要再创建一个唯一的根节点模板,里边可以直接放文本内容或者很多同级的标签。在Vs code中需要升级你的
Vetur
插件,否则模板中如果没有唯一的根据点VS Code依然会提示有错误。左边是我们刚刚看到的组件模板中的内容,右边是我们编译之后的render函数,但是这个编译的结果跟Vue2会有很大的区别,首先这里调用
_createBlock
给我们的根div
创建了一个block
,它是一个树的结构,然后通过createVNode
的去创建了我们的子节点,那这里的createVNode
的其实就是类似于我们之前的h
函数。那我们来删除这里面的根节点,来看一下它的变化。
当我们删除根节点之后,这里会创建一个
fragment
,也就是我们之前说的片段。其实从这里还可以看到,它内部还是维护了一个树形的结构,那么最外层是fragment
,里边是我们的这些VNode
的。
Vue 2.x中通过标记静态根节点,优化diff的过程
源码体积的优化
Options Api
中可以发现要实现一个功能,需要在不同选项中添加。如果此时需要在添加一个功能,就需要在多个选项中添加代码。并且难以提取组件中重复的代码。
data
、methods
、props
等)的对象mixin
,但容易命名冲突,数据来源不清晰。首先来看一下响应式系统升级。我们都知道Vue2的时候,数据响应式的原理使用的是defineProperty
,在初始化的时候会遍历data
中的所有成员。通过defineProperty
,把对象的属性转换成getter
和setter
。如果data
中的属性又是对象的话,需要递归处理每一个子对象的属性。注意这些都是在初始化的时候进行的。也就是说如果你没有使用这个属性的时候,你也把它进行了响应式的处理。
而Vue3中采用的是ES6
以后新增的proxy
对象。proxy
对象的性能本身就比defineProperty
要好。另外,代理对象可以拦截属性的访问、复制、删除等操作。不需要初始化的时候遍历所有的属性。另外,如果有多层属性嵌套的话,只有访问某个属性的时候,才会递归处理下一级的属性,使用proxy
对象默认就可以监听到动态添加的属性。而Vue2里边想要动态添加一个显示的属性需要调用this.$set
的方法来处理。而且Vue2中还监听不到属性的删除,对数组的索引和length属性的修改也监听不到。Vue3中使用代理对象可以监听属性的删除以及数组的索引和length属性的修改操作。所以Vue3中使用proxy
对象提升了响应式系统的性能和功能。
Vue3中通过优化编译的过程和重写虚拟DOM
,让首次渲染和更新的性能有了大幅度的提升。我们知道Vue2的时候,模板首先需要编译成render
函数,这个过程一般是在构建的过程中完成的。在编译的时候会编译静态根节点和静态节点。静态根节点要求节点中必须有一个静态子节点,当组件的状态发生变化后,会通知watch
触发watcher
和update
。最终去执行虚拟DOM
的patch
操作遍历所有的虚拟节点,找到差异,然后更新到真实DOM
上。
Diff
的过程中会去比较整个虚拟DOM
,先对比新旧的div
以及它的属性,然后再对比它内部的子节点。Vue2中渲染的最小单位是组件。Vue2中diff
的过程会跳过静态根节点,因为静态根节点的内容不会发生变化,也就是Vue2中通过标记静态根节点优化了diff
的过程。但是在Vue2的时候,静态节点还需要再进行diff
,这个过程没有被优化。
Vue3中为了提高性能,在编译的时候会标记和提升所有的静态节点,然后diff
的时候只需要对比动态节点的内容。另外在Vue3中新引入了一个Fragments
,也就是片段的特性,模板中不需要再创建一个唯一的根节点模板,里边可以直接放文本内容或者很多同级的标签。
Vue3的响应式系统默认可以监听动态添加的属性,还可以监听属性的删除操作以及数组的索引和length
属性的修改操作。另外Vue3的响应式系统还可以作为一个模块单独使用。