前言
vue 3.0 源码刚出没多久 本人日常开发惯用vue 以前看过 vue 2.0 的一些源码 此次准备作一次逐行分析 3.0 的源码 欢迎你们在下方留言 你们一块儿讨论。javascript
vue 3.0 源码特点:
- 结构清晰
经过yarn的工做区方式,简单来讲就是功能模块按照package.json下的workspace字段,解耦划分红一个个文件夹(自带package.json,不懂的跳转:yarn 文档),每一个功能能够本身 yarn dev 编译出相应模块文件,换句话说 vue 3.0 的响应式模块 彻底能够抽离出来用做其余项目 这是以前vue 2.0 作不到的
- Typescript重构
以前vue 2.0 是用 Flow 来作静态类型代码检查,后面发现这个团队不靠谱 Flow项目烂尾了,根本拼不过微软大大的TS,如今TS的前端市场占比也很高,所以本次也是直接狠下心用Typescript重构了。
以前本人有个项目用了vue+TS,但总以为本身的使用很初级,高阶使用 如范型之类的,都没有落地接触过,这个源码中有很是多的TS最佳实践,高阶TS使用。因此看这个源码还能同时很好地学习 TS ,一箭双雕。
- Proxy改造
看过2.0源码的或者稍微了解过vue响应式原理的都知道2.0使用的是Object.defineProperty作数据劫持的。此次也是直接改形成Proxy(ES6语法),性能不像Object.defineProperty须要一上来就遍历全部,性能更加优异,下面会继续讨论这块的。
vue 3.0 源码如何有效地看呢:
- 必看
主目录的package.json,每一个项目应该首先看这个文件。由于它可让咱们了解源码支持哪些scripts,好比 test 咱们能够yarn test跑一下测试脚本试试。workspace字段表明工做区的内容即功能模块代码位置,就很少说了。
还有一些前端工程化发布流程相关的加餐知识,学到了也能够应用到本身的项目中,这块能够下节附赠给你们。
- 先关注某个功能模块的主流程
前面说了 workspace 的概念,咱们能够从其中一个功能模块开始,看主流程文件,中间遇到函数回调,先看字面意思,看完主流程再去一个个切进去深刻看。如:先从 reactivity 文件夹下的 reactive.ts 响应式主流程看起。
- 语法文档
由于有不少 TS / ES6 的语法,建议配合着 TS 文档及 ES6 语法来看,遇到不会的语法赶忙查
- yarn dev
调试源码,编译生成相应文件,本身写一个html引入来测试,这块下节给你们说一下
正文
先看这块,我将源码的注释翻译了一下,感受仍是不够立体,须要品味一番
html
语法上看,用到了 TS 的范型接口的概念
- 什么是泛型,这是一种 OOP 后端语言经常使用的概念,即下图中的<T>,能够从字面的意思推导出: 泛指的,不肯定的类型。传进来什么类型后续就用什么类型,好比这里Set若是传入Number类型,add方法的入参也必须是Number类型
- 为何说是接口,由于 TS 核心对 ES6 的 Set Map WeakSet WeakMap都作了封装 写入 TS 声明文件(.d.ts),这样 TS 就能对这些类型进行类型推断,静态检查
语义上看,主要是为了构造 targetMap 这个存储依赖关系的WeakMap 这里用WeakMap的缘由在于,WeakMap键名所引用的对象都是弱引用,即垃圾回收机制不将该引用考虑在内,不影响引用计数,只要其余引用都清除,垃圾回收自动回收掉该对象内存,正好适合该场景:你须要存储proxy化的target对象,一旦其余target对象引用清除,这边targetMap也须要自动清除该对象,有助于防止内存泄漏。
目的就是为了构造出下方这种格式,具体 Dep 的泛型 ReactiveEffect 是什么须要到 effect.ts再看,如今关注这个结构。
{
target:{
key: Dep
}
}
复制代码
再看下一块 前端
这边源码注释翻译就是这4个weakmap存储着原始数据到观察者的映射 这里注意这个<->符号表明的是双向的,即原始数据 -> 观察者,观察者 -> 原始数据。
这边为何要存储双向的,应该仍是从
经过牺牲空间复杂度来换取更高效的时间复杂度考虑,由于这样存储获取的时间复杂度是O(1),而且还能得到一些其他的好处好比一些自带的性能极佳的方法
这边主要是作了一些预备操做,好比声明集合的类型,正则表达式等,以及是否可观察的函数,这边我已经注释了,对主流程没有太大影响。
接下来属于核心流程
vue
对外暴露的reactive方法是proxy化,这边对只读数据进行了特殊处理readonly函数,这里还须要对值作判断,若是这个值是响应式的proxy直接返回响应式版本。其实最后的核心proxy化步骤都是createReactiveObject这个函数
这边是proxy化的核心流程,其实看着仍是比较简单,主要是proxy的handler这一块下一节会深刻进去。
最后是一些对外暴露的函数,字面意思应该都看得懂,这里注意获取原始数据这里,最后直接或操做符了observed,有两种可能,一种是非可观察的白名单即上文所提到的,一种是基本数据类型
尾言
这节主要讲了响应式的核心文件及主流程,内容并不复杂,有问题能够下方留言,互相讨论。下节会深刻到文件effect.ts,这块也是源码中理解的难点,而且会附送源码中的一些工程化的实践。java