
在看 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 Dec 10, 2021 addDep 是将当前 watcher 收集到 dep 中。 关键在这一句:dep.addSub(this); |
2 unsized Dec 10, 2021 dep 记录了订阅者列表,也就是 watcher 。当 watcher 销毁时,要把它自己从 dep 的订阅者列表中移除,来避免下次 dep 更新时,再来通知这个已经销毁的 watcher 。 |
4 RyanLim Dec 10, 2021 @tyx1703 +1 ,不能说是相互收集,可以理解为类似,双向链表,要断链表的话需要 parent.removeChild ,children.removeParent 。 |
5 ryncv Dec 10, 2021 如果你说的是 newDepIds 那行判断的话,主要是为了避免收集重复依赖,比如在模板中写了两个{{user}}{{user}},直接 addSub 就会被重复收集一次。 详细的可以看看这里 http://caibaojian.com/vue-design/art/8vue-reactive-dep-watch.html#%E5%88%9D%E8%AF%86-watcher |
6 rebel28 Dec 10, 2021 大脑里面走一遍流程 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 循环通知 //个人理解 |