在看 Vue 源码的时候发现很困惑的一点,Dep 会收集 Watcher ,然后提供出方法来执行所收集 Watcher 的 update 方法
src/core/observer/dep
export default class Dep {
static target: ?Watcher;
...
addSub (sub: Watcher) {
this.subs.push(sub)
}
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
notify () {
...
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
...
}
看到这没什么问题,但在我继续往下看,想了解 Dep 如何收集 Watcher 的时候,我陷入了怪圈
看的路径大致如下:
想知道:Dep 实例的 addSub ==> 找到了 Wacher 实例里有个方法 addDep ,会调用 addSub(this)进行赋值
??因为 Watcher 也会收集 Dep ,这时候我开始有点逻辑混乱,为什么要收集 Dep ,算了先不管
找什么地方用了 Watcher 的 addDep ==> 找到了 Dep 的 depend 方法,如上面代码所示
继续找 Dep 的 depend 方法 ==> 在 Watcher 里找到了。。。把我套死在这了
export default class Watcher {
...
addDep (dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}
depend () {
let i = this.deps.length
while (i--) {
this.deps[i].depend()
}
}
}
后面以 Dep.target 为突破口找到了 component mounted 里会 new 一个 Watcher, 勉强理解了视图 Watcher 怎么添加的,大概是 new Watcher+访问被添加了响应式的数据(全靠猜)
但是 Watcher 为什么要收集 Dep ?晕在了上面这段逻辑
1
ryncv 2021-12-10 17:11:26 +08:00
addDep 是将当前 watcher 收集到 dep 中。
关键在这一句:dep.addSub(this); |
2
tyx1703 2021-12-10 17:15:46 +08:00
dep 记录了订阅者列表,也就是 watcher 。当 watcher 销毁时,要把它自己从 dep 的订阅者列表中移除,来避免下次 dep 更新时,再来通知这个已经销毁的 watcher 。
|
3
jzlivioo OP @ryncv 可是 addSub 是 Dep 用来收集 Watcher 的,为什么 Watcher 收集 Dep 的方法中会调用这个?
|
4
RyanLim 2021-12-10 17:27:52 +08:00
@tyx1703 +1 ,不能说是相互收集,可以理解为类似,双向链表,要断链表的话需要 parent.removeChild ,children.removeParent 。
|
5
ryncv 2021-12-10 17:49:46 +08:00
如果你说的是 newDepIds 那行判断的话,主要是为了避免收集重复依赖,比如在模板中写了两个{{user}}{{user}},直接 addSub 就会被重复收集一次。
详细的可以看看这里 http://caibaojian.com/vue-design/art/8vue-reactive-dep-watch.html#%E5%88%9D%E8%AF%86-watcher |
6
violetlai 2021-12-10 17:52:52 +08:00
大脑里面走一遍流程
1.第一遍在 defineReactive 第一次实例化了 dep 2.编译 compile 的时候走到了 new Watcher 然后走到了 addDep 这时候给 target 赋值把自己( Watcher 实例)添加到 Dep.target 这个静态方法里面 但是没有更改属性 就没有添加 这个 watcher 就没有办法循环通知 if (Dep.target) {// false Dep.target.addDep(this) } 3.改变了属性 if (Dep.target) {// true Dep.target.addDep(this) } 添加到了 dep 里面 然后触发 set 循环通知 //个人理解 |