Vue3 设计思想
# # Vue3 设计思想
* [1\. Vue3 设计目标](#_1-vue3-设计目标)
* [1.1 更快 - Proxy](#_1-1-更快-proxy)
* [1.2 更快 - Virtual Dom 重构](#_1-2-更快-virtual-dom-重构)
* [1.3 更快 - 更多编译优化](#_1-3-更快-更多编译优化)
* [2\. Vue 设计思考](#_2-vue-设计思考)
* [2.1 Scope](#_2-1-scope)
* [2.2 JSX vs Template](#_2-2-jsx-vs-template)
* [3\. 参考](#_3-参考)
2
3
4
5
6
7
8
# # 1. Vue3 设计目标
- 更小 -> tree shaking
- 更快
- Object.defineProperty -> Proxy(使得初始化不用再递归data)
- Virtual Dom 重构 -> 利用模板代码,确定动态和静态代码,在VDom Diff时优化
- 可跳过静态文本(无需递归进入子树循环),可跳过props对比
- 事件监听函数cache
- 更多编译优化 -> 利用模板代码,尽可能预先优化编译的代码
- slot默认编译为函数(不存在父子组件强耦合)
- Momomorphic vnode factory
- Compiler-generated flags for vnode/children types(VNode带上类型)
- 加强TypeScript支持
- 加强API设计一致性
- 提高自身可维护性
- 开放更多底层功能
- 响应式数据监听(即Vue2.x的Object.observer)
# # 1.1 更快 - Proxy
Proxy减少了组件实例初始化开销。在Vue2中,初始化组件时
会对data的属性递归调用包装(Object.defineProperty);而在Vue3中,初始化只是书写Proxy的代理handler(Proxy包装),当运行时
getter某个属性时,才去重新Proxy包装该值,减少了初始化组件的时间。Vue3此部分源码讲解 (opens new window) (opens new window)
ES6 Proxy数据监听优点:
- 对对象进行直接监听, 可以
弥补Object.defineProperty无法监听新增删除属性的短板
无需再遍历对象进行设置
监听函数Object.defineProperty- 可以
适用于Array
, 不需要再分成两种写法
# # 1.2 更快 - Virtual Dom 重构
VDOM作用, 状态(或者叫数据)驱动UI,开发者只考虑状态改变,而UI会自动变化,这就是VDOM的最大价值。
所以在VDOM基础上,UI不仅可以是DOM元素(web端),也可以是Native(移动端)。
# # 传统Virtual DOM的性能瓶颈
数据变更之后,新的Virtual DOM和旧的Virtual DOM进行 patch 算法比较,并算出二者之间的差异,将差异进行修改。但是传统Virtual DOM,进行算法比对时颗粒度是组件,每个组件作为一个颗粒。
虽然Vue能够保证触发更新的组件最小化,但是单个组件内部依然需要遍历该组件的整个Virtual DOM树。
传统Virtual DOM的性能跟模板大小正相关,跟动态节点的数量无关。模板或者组件有多大,那么在进行数据更新时损耗的性能就有多大,但实际上,这种方式利用率很低。如上图所示,在上述template中,发生改变的地方只有message插值的部分,整体结构不变,但是数据更新的时候,比对整个template结构,这样就存在性能损耗。 所以在一些组件整个模板内只有少量动态节点的情况下,传统方法遍历存在性能的浪费。
# # Vue3.0 Virtual DOM
如果要追求极致的性能,最快速的就是利用模板进行数据监听,当数据变化时,直接更新对应的DOM元素(此时可以不用VDOM,Svelte (opens new window) (opens new window)框架就是无VDOM)。这种方式适合开发纯template模板,因为一旦模板确定,就可以根据模板进行预编译,简单高效。
但这种开发方式有个弊端,无法利用js的灵活性。当开发者使用render function/JSX时,根本无法预知代码意图,所以Svelte书写上无法支持render function/JSX。Vue3所要做的:保留VDOM,兼容手写render function,同时最大化利用模版静态信息。
# # 解决方案
动静结合
,找到动态变化的部分,更新时只对比可以变化的部分,减少性能损耗。
实现上,就是在模板编译时,给各个VNode带上type类型,区分不同的变更需求,然后在VDOM时对不同type的VNode更新做优化处理
。Vue3重构的VDOM源码讲解,会在往后单独开一篇文章讲解,这里把核心源码贴上:
- Vue3 DOM算法:https://github.com/vuejs/vue-next/blob/master/packages/runtime-core/src/renderer.ts
- Vue2 DOM算法:https://github.com/vuejs/vue/blob/dev/src/core/vdom/patch.js
# # 1.3 更快 - 更多编译优化
主要是利用模板代码的可预见性,在编译时做好编译优化
- 优化slots生成。slot编译时统一为函数(v-slot),父子组件slot渲染分离。
- 静态内容提取。模板不变时,diff跳过(Vue2已优化)
- 静态属性提取
- 内联函数提取
# # 2. Vue 设计思考
# # 2.1 Scope
框架职责,React主要聚合在底层,不会像Angular一样大包大揽,拥有Route、Form解决方案等。
- Scope小
- 优点:只关注底层,不用再维护额外的解决方案,都丢给社区。上手快,因为记忆小。
- 缺点:解决方案分散(另一个维度,造就社区繁荣)
# # 2.2 JSX vs Template
- JSX:
- 优点:完整的JS表达能力、视图即数据
- 缺点:VDOM难以优化,因为js动态性,无法预先优化
- Template
- 优点:可以预先优化VDOM
# # 3. 参考
以上思想主要来自Vue作者尤雨溪的多个VueConf大会视频,笔者在理解基础上进行总结,建议读者完整看原视频。