Proxy减少了组件实例初始化开销。在Vue2中,初始化组件时
会对data的属性递归调用包装(Object.defineProperty);而在Vue3中,初始化只是书写Proxy的代理handler(Proxy包装),当运行时
getter某个属性时,才去重新Proxy包装该值,减少了初始化组件的时间。Vue3此部分源码讲解 (opens new window)
ES6 Proxy数据监听优点:
弥补Object.defineProperty无法监听新增删除属性的短板
无需再遍历对象进行设置
监听函数Object.defineProperty适用于Array
, 不需要再分成两种写法VDOM作用, 状态(或者叫数据)驱动UI,开发者只考虑状态改变,而UI会自动变化,这就是VDOM的最大价值。
所以在VDOM基础上,UI不仅可以是DOM元素(web端),也可以是Native(移动端)。
数据变更之后,新的Virtual DOM和旧的Virtual DOM进行 patch 算法比较,并算出二者之间的差异,将差异进行修改。但是传统Virtual DOM,进行算法比对时颗粒度是组件,每个组件作为一个颗粒。
虽然Vue能够保证触发更新的组件最小化,但是单个组件内部依然需要遍历该组件的整个Virtual DOM树。
传统Virtual DOM的性能跟模板大小正相关,跟动态节点的数量无关。模板或者组件有多大,那么在进行数据更新时损耗的性能就有多大,但实际上,这种方式利用率很低。如上图所示,在上述template中,发生改变的地方只有message插值的部分,整体结构不变,但是数据更新的时候,比对整个template结构,这样就存在性能损耗。 所以在一些组件整个模板内只有少量动态节点的情况下,传统方法遍历存在性能的浪费。
如果要追求极致的性能,最快速的就是利用模板进行数据监听,当数据变化时,直接更新对应的DOM元素(此时可以不用VDOM,Svelte (opens new window)框架就是无VDOM)。这种方式适合开发纯template模板,因为一旦模板确定,就可以根据模板进行预编译,简单高效。
但这种开发方式有个弊端,无法利用js的灵活性。当开发者使用render function/JSX时,根本无法预知代码意图,所以Svelte书写上无法支持render function/JSX。Vue3所要做的:保留VDOM,兼容手写render function,同时最大化利用模版静态信息。
动静结合
,找到动态变化的部分,更新时只对比可以变化的部分,减少性能损耗。
实现上,就是在模板编译时,给各个VNode带上type类型,区分不同的变更需求,然后在VDOM时对不同type的VNode更新做优化处理
。Vue3重构的VDOM源码讲解,会在往后单独开一篇文章讲解,这里把核心源码贴上:
主要是利用模板代码的可预见性,在编译时做好编译优化
框架职责,React主要聚合在底层,不会像Angular一样大包大揽,拥有Route、Form解决方案等。
以上思想主要来自Vue作者尤雨溪的多个VueConf大会视频,笔者在理解基础上进行总结,建议读者完整看原视频。