1 为什么要依赖收集?
栗子
1. new 一个 Vue 实例
new Vue({
template: `
<div>
<span>{{ text1 }}</span>
<span>{{ text2 }}</span>
</div>
`,
data: {
text1: 'text1',
text2: 'text2',
text3: 'text3'
}
})
2. 执行操作 this.text3 = "modify text3"
因为视图并不需要用到 text3,所以我们并不需要触发
cb
函数来更新视图
栗子
1. 在多个 Vue 实例中用到同一个对象(全局对象)
let globalObj = {
text1: 'text1'
};
let o1 = new Vue({
template: `
<div>
<span>{{ text1 }}</span>
</div>
`,
data: globalObj
});
let o2 = new Vue({
template: `
<div>
<span>{{ text1 }}</span>
</div>
`,
data: globalObj
});
2. 执行操作 globalObj.text1 = 'hello text1'
依赖收集会让 text1 这个数据知道需要通知 o1 和 o2 两个 Vue 实例进行视图的更新
- 形成数据与视图的一种对应关系
![](https://img2020.cnblogs.com/blog/1891336/202101/1891336-20210126170048552-1205106000.png)
2 如何实现依赖收集?
2.1 订阅者 Dep
实现订阅者 Dep:用来存放 Watcher 观察者对象
用
addSub
方法可以在目前的Dep
对象中增加一个Watcher
的订阅操作
用notify
方法通知目前Dep
对象的subs
中的所有Watcher
对象触发更新操作
class Dep {
constructor () {
// 用来存放Watcher对象的数组
this.subs = [];
}
// 在subs中添加一个Watcher对象
addSub (sub) {
this.subs.push(sub);
}
// 通知所有Watcher对象更新视图
notify () {
this.subs.forEach(sub => {
sub.update();
})
}
}
2.2 观察者 Watcher
class Watcher {
constructor () {
// 在new一个Watcher对象时将该对象赋值给Dep.target,在get中会用到
Dep.targer = this;
}
// 更新视图的方法
update () {
console.log('视图更新啦~');
}
}
Dep.target = null;
2.3 依赖收集
修改 defineReactive
以及 Vue 的构造函数
增加 Dep
类,用来收集 Watcher
对象
-
在对象被 读 时,会触发
reactiveGetter
方法把当前的Watcher
对象(存放在Dep.target
中)收集到Dep
类中去 -
当该对象被 写 时,会触发
reactiveSetter
方法,通知Dep
类调用notify
来触发所有Watcher
对象的update
方法更新对应视图
function defineReactive (obj, key, val) {
// Dep类对象
const dep = new Dep();
Object.defineProperty(obj, key, {
enumberable: true,
configurable: true,
get: function reactiveGetter () {
// 将Dep.target(当前Watcher对象)存入dep的subs中
dep.addSubs(Dep.target);
return val;
},
set: function reactiveSetter (newVal) {
if (newVal === val) return;
// 在set时触发dep的notify来通知所有的Watcher对象更新视图
dep.notify();
}
})
}
class Vue {
// Vue构造类
constructor (options) {
this._data = options.data;
// 新建一个Watcher观察者对象,此时Dep.target会指向这个Watcher对象
new Watcher();
// 模仿render的过程,为了触发test属性的get函数
console.log('render~', this._data.test)
}
}
总结
- 在
observer
的过程会注册get
方法,用来进行依赖收集 - 该闭包
observer
中会有一个Dep
对象,用来存放Watcher
对象的实例
3 Object.defineProperty 的set/get方法所处理的事情:
- 依赖收集的过程就是把
Watcher
实例存放到对应的Dep
对象中,get
方法可以让当前的Watcher
对象(Dep.target
)存放到它的subs
中(addSub
),在数据变化时,set
会调用Dep
对象的notify
方法通知它内部所有的Watcher
对象进行视图更新。
依赖收集的前提条件
-
触发
get
方法 -
新建一个
Watcher
对象