刚刚看了
Vue.js
作者在VueConf 2019
上海的演讲视频,学习到了很多的东西。了解了vue
在全球的影响力、活跃的社区以及核心开发团队,更主要的是vue2
当前的一些问题和在vue3
中的一些进步。下面我总结了从中学习到的几点。
vdom
1. 性能瓶颈
新vdom生成:
当数据更新时,虽然vue可以定位到最小更新粒度为组件级别,但在组件级别内,还是需要重新遍历模板生成新的vdom
,更新粒度不够小。
diff算法:diff
的工作量和组件模板大小成正相关。即使模板内只有少量的动态节点,也需要遍历整个组件去执行diff
。
总结:vdom
的更新粒度不够灵活,导致生成新的vnode
和新旧vnode diff
过程中,做了很多无用功,导致浪费性能.
2. 原因
vdom
是从react
而来的,jsx
和手写的render function
是完全动态的,过度的灵活性导致无法收集优化的信息,即你无法解读js
的代码,来区分静态节点和动态节点。
如下图,很难识别出:只有div
下的第二个p
是动态节点。
3. 解决方案
react
时间分片
在动态节点和数据的量都很大时,那么在数据更新时,js
线程就会用很长的时间来执行vdom
的相关计算,如果超过了16ms,造成交互或动画等等卡顿现象。而时间分片就是把vdom
的大量计算分成多个小任务,保证每个小任务在16ms内执行完,从而不会阻塞用户交互,避免卡顿现象。
即react
承认vdom
的这些缺点,然后它从其他的层面来弥补缺点带来的问题。
vue
缩小更新粒度
最大化利用的模板信息,把更新的粒度从组件缩小到代码块。
即从组件模板中提取出动态节点、动态代码块,做diff
时,只需要比较这些动态区域,而忽略掉静态节点,从而提升性能。
再比如一个节点仅仅
class
属性为动态的,那么只需要diff
这一个属性即可。进一步提升了性能。
总结:vdom
的更新性能将与动态内容的数量相关,而不是模板整体大小。
function-based API
优势1:更好的支持TS类型推导
优势2:Tree-shaking友好
常用的API value
、computed
、watch
等都是从vue
中使用import
引进来的,所以支持tree-shaking
。即如果没有使用这些api,那么这些相应的代码就不会被打包,缩小了文件大小。
优势3:代码更容易被压缩
对象属性一般是不会被压缩的,而变量名是可以被压缩的
优势4:逻辑复用
逻辑复用有很多种方案,都有一些缺点:
1. mixins
- 命名空间冲突(多个mixins,不能保证变量名不会冲突)
- 数据来源不清晰(多个mixins时,使用的变量就不易分辨它的来源)
2. 高阶组件
- props命名空间冲突
- props数据来源不清晰
- 额外的组件实例性能消耗
3. 作用域插槽
- 额外的组件实例性能消耗
而在vue3中逻辑复用会有不同的方式:
可以发现和
react hook
逻辑封装形式很像,就是在组件内定义响应式的变量,并封装变量更改的逻辑,在最后把变量暴露出来,供其他组件使用。