记一次阅读 Vue 源码的总结.
响应式原理
Vue 通过响应式在修改数据的时候更新视图。
在官网 copy 的介绍响应式原理的图.
流向为: model -> view
可以对表单元素v-model
来进行双向数据绑定.
数据劫持 & 将数据变成可观察的(Observable)
1 | // observer/index.js |
小结
1 | function initData(vm: Component) { |
Vue
在其初始化时调用observe
方法,为data
对象的每个属性利用Object.defineProperty()
方法给每个属性添加getter
, setter
,让每个属性都变成observable
(可观察的).如果属性的value
为一个对象的话,那么内部会递归调用observe
方法来给子对象的属性创建观察者实例,使其变为observable
的.
(其实还会将 template 上的每个v-
指令还有computed
,props
的数据全部转化为observale
)
当 Vue 进行 render 时,需要取数据,就会触发getter
,进行依赖收集, (将订阅者(watcher)和观察者观察的(data)绑定起来),修改某一个可观察属性时,就会触发该属性的setter
,通知订阅者(watcher)进行更新操作.
依赖(dependence)Dep
这个 dep 对象上可以挂载多个订阅者
1 | /** |
小结
读取数据,触发observable
data
的 getter,通过Dep
将 data 与订阅者添加一个依赖关系。一个 data 对应一个Dep
实例,其有一个 uniqueID,用来标识,其内部维护一个subs
订阅者数组。当 data 改变,触发 setter,会通过Dep
实例来给 subs 里的所有订阅者通知更新。
Watcher 订阅者
订阅者主要作用:
- 通过 Dep(依赖)来为每个数据添加订阅者,当数据变化时,会通过
Dep
来通知订阅者进行update
操作. - 创建订阅者实例会传入一个 cb 函数,当 update 执行完后会执行这个 cb 函数。cb 函数是用来执行 re-render 操作的,用于将新数据重新渲染到 view 上.
这里就贴我自己写的watch
1 | import Dep from './dep' |
对三者的一个小结
首先是组件渲染函数,进行一次 render 操作就会取到所有的数据,这时就会触发 getter,(这里只取到了视图渲染需要的数据触发 getter),从而进行依赖收集,Data
可以看成与Watcher
绑定在一起,但是我们知道他们中间是有个Dep
在维护的他们的关系的,当触发 getter 时,将 watcher 添加到 Dep 的subs
数组。数据改变时,触发 setter,Dep
通知subs
里的所有 watcher【你订阅的数据改变了】,watcher 会触发 update,而实际工作是由run
来执行,判断新旧数据是否一致,如果数据真的改变了,则会触发 watcher 实例的 cb 函数,继续将工作交给 compiler 来做,最终结果会重新渲染视图(一般是渲染部分视图),因为 vue 也采用了 virtual DOM 技术,(用 JS 对象来模仿 DOM 节点,避免多次直接 DOM 操作,提高性能)监听到 VNode 变化时,会先通过 diff 算法,判断初始虚拟 DOM 树和改变后的虚拟 DOM 树是否有差别,具体哪里发生改变,思想是修改尽量少的 DOM,进行尽量少的 DOM 操作,最后把发生改变的虚拟 DOM 元素应用到真实 DOM 上.(patch
操作)
再看上图. touch
在源码watcher.js
也看到touch
,关于这个我自己是这样理解的.
1 | //observer/watcher.js |
“touch” every property so they are all tracked as dependencies for deep watching
这里应该是来对值为object
or array
的进一步处理, 触发每个深层对象的依赖.
图中的touch
也可以理解为访问’touch’ every needed property,多了个 needed,就是访问所有需要用到的属性.
自己的实现
模仿 Vue 完成小作业, 因为还没有去看 Vue 的模版渲染,所以就只实现了 Observer、Dep、Watcher 这三者的逻辑关系,最终结果一个简单的观察订阅者模式的 demo。
题外话
浅尝辄止,这个词,来形容过去的学习生活,可以说是很形象很贴切了。
最近也是在忙春招,也是会有点紧张和压抑,原因,浅尝辄止
。
反正,加油啦。自我安慰(学东西,慢一点没关系啦)。
也是自己第一篇源码相关的总结,学习到不少,这篇主要还是给源码根据自己的理解添加中文注释,可能由很多地方有误。