上节内容主要介绍了一下新的Vue所依赖的响应式数据方案Proxy所带来的性能提升,其实劫持了整个对象除了提升了性能之外,更重要的是对于实现方案的优化,由于对象本身的功能限制,Object.defineProperty并不支持Map\Set,对于习惯使用这两种对象的同学们来说,这不得不说是一大遗憾,只能选用数组执行,但对数组基于下标的修改和对于.length变化的监测又不够友好。而使用Proxy显然是解决了这些问题。
本节内容我们继续探索一下Vue3对于性能方面的优化所做的努力-》重写虚拟DOM:
我们知道,Vue采用了virtual-dom,其核心的diff算法让我们不需要再去操心dom渲染问题,但virtual-dom是目前最快的虚拟dom实现方案吗?
答案是否定的,浩瀚的网络中,总有对单一目标执着的猿,执着的向着‘更快’前进:
通过JS Web框架基准测试,当前虚拟dom实现方案的性能排序如下
Vue自然不可能掘根式的将自己的virtual-dom给替换成Inferno,但其中的一些优化技巧,却是可以学习的。这次改造,使得Vue的整体性能提升了一倍,最直接的体现是应用的启动时间将缩短一半。
同时,新的虚拟dom实现带来的性能提升,使得Vue可以执行一些更加高效的编译耗时优化,静态树的提升、静态属性的提升,以及为运行时提供来自编译器的提示等。
关于这一块,我们并不需要深入的了解其原理,因为这一块的升级是润物细无声的,既没有新的api,也没有新的功能点使用,但确实是性能得以提升的核心,在这里我们不做深刻的讨论对比Vue与inferno的优劣。感兴趣的同学可以自己深入了解一下。
https://infernojs.org/benchmarks
好的,关于3.0的简述到此为止,接下来,我们开始读一下已经放出来的Vue3.0的源码,咱们从源码,触控一下3.0的灵魂
在此之前,你需要了解一下:
Proxy
Symbol
Map
Set
这些在3.0中大量使用到的对象,然后最好具有TypeScript的相关知识,这点很重要,即将发布的3.0将全面支持TypeScript的语法标准,毕竟强类型的开发语言可以有效降低程序的类型问题。
放一下git传送们:https://github.com/vuejs/vue-next
我们可以先看一下3.0的包文件夹,通过阅读他们的Readme文档,我们可以看出自上往下分别是:运行时构建的入口和其独立构建版本,reactivity,运行时的代码,针对浏览器的runtime代码,为了测试而些的轻量级runtime,服务端渲染,共享模块,模板编译输出的实时资源管理器和Vue的模型。
我们可以逐个解读一下这些模块的功能。
先从看起来就比较奇怪的reactivity开始吧~!
reactivity是响应式系统的数据观测核心代码,打开Readme,文档中清晰写明了”这个包被内联到面向用户的渲染器的构件中,但也可以作为独立使用的包发布”还有一些公开的api,我们可以去index.ts中查看。
然后我们可以从Vue3入门到放弃了~本篇文章到此结束,感谢各位的收看。
开玩笑,开玩笑,各位请先别动手,咱们继续往下分析
入口文件列出了所有对外的api模块与依赖内容,目前我们还不知道各个模块的功能与含义,咱们继续拆分即可。
其中ref与reactive是源码中的入口和核心模块,响应式数据即是通过这两个方法创建的,我们必须先理解这两个部分,才能理解整个reactivity。
这里是ref.ts中的内容,我们可以看到,其中主要有ref、isRef、toRefs、等方法组成,我们从上往下看,Ref的数据结构由两部分组成,用_isRef做类型的标识,用value进行数据存储,通过最下面的解构方法,我们可以看出,对于每一种类型的嵌套,都进行了解析,不过需要注意的是,在第66行的部位,明确的表示了不能被解套的复杂数据类型。
继续往下分析,ref函数具体的实现了Ref类型的数据,在ref函数中,当遇到了非Ref类型的数据的情况下,会生成了一个数据结构,由_isRef,get,set组成,最后会返回一个Ref类型的数据,在这个里面,调用了一些其他模块的方法,我们可以在读到这一块的源码的时候,再着重的去了解track和trigger,看这两个暴露出的方法的目的是什么。
有的同学可能看到这里会有些疑惑,你之前一直在提,一直在强调的Pxoxy呢!什么性能提高多少多少!为什么一点也没有看到!?你是不是在匡人?
这个,当然并不是了,不要着急,我们马上就要分析到了这一块了
实际上,创作团队在ref函数中,创建了一个对象,也就是刚才的那个数据结构,然后将这我们的原始数据存在了ref的value中,然后再把引用返回给了使用者,由于这个对象是我们自己创造出来的,就完全不需要proxy再做一个代理,我们直接劫持这个value的get/set就可以了。但这样写还有一个缺点,就是只能保持基本数据类型实现响应式,并没有实现对对象的解构,于是创作团建又创建了一个toRefs函数解决这个问题,在这个函数中,通过遍历对象所有的key,调用了toProxyRef方法,将其所有的值都转化为Ref的数据。这样就保证了所有的数据都具有了响应式数据的引用。作者在想,如果往toRef中注入了一个Ref对象会返回什么呢?
好的,读到了这里,ref中的内容我们已经读的差不多了,下一章我们看一下核心的reaactive,看看模块同名文件,要实现的是什么。
才疏学浅,可能分析的有所瑕疵,感谢各位老师的指正,最后,作者在这里恭祝大家节日快乐了。来都来了,都看到这了,你不点个赞再走吗?
参考链接
https://juejin.im/post/5bb719b9f265da0ab915dbdd