求助, Vue 的观察者模式里, Dep 和 Watcher 是如何确立对应关系(依赖收集)的? - V2EX
V2EX = way to explore
V2EX 是一个关于分享和探索的地方
Sign Up Now
For Existing Member  Sign In
请不要在回答技术问题时复制粘贴 AI 生成的内容
jzlivioo

求助, Vue 的观察者模式里, Dep 和 Watcher 是如何确立对应关系(依赖收集)的?

  •  
  •   jzlivioo Dec 10, 2021 1875 views
    This topic created in 1601 days ago, the information mentioned may be changed or developed.

    在看 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 ?晕在了上面这段逻辑

    6 replies    2021-12-10 17:52:52 +08:00
    ryncv
        1
    ryncv  
       Dec 10, 2021
    addDep 是将当前 watcher 收集到 dep 中。
    关键在这一句:dep.addSub(this);
    unsized
        2
    unsized  
       Dec 10, 2021
    dep 记录了订阅者列表,也就是 watcher 。当 watcher 销毁时,要把它自己从 dep 的订阅者列表中移除,来避免下次 dep 更新时,再来通知这个已经销毁的 watcher 。
    jzlivioo
        3
    jzlivioo  
    OP
       Dec 10, 2021
    @ryncv 可是 addSub 是 Dep 用来收集 Watcher 的,为什么 Watcher 收集 Dep 的方法中会调用这个?
    RyanLim
        4
    RyanLim  
       Dec 10, 2021
    @tyx1703 +1 ,不能说是相互收集,可以理解为类似,双向链表,要断链表的话需要 parent.removeChild ,children.removeParent 。
    ryncv
        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
    rebel28
        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 循环通知

    //个人理解
    About     Help     Advertise     Blog     API     FAQ     Solana     3160 Online   Highest 6679       Select Language
    创意工作者们的社区
    World is powered by slitude
    VERSION: 3.9.8.5 36ms UTC 14:12 PVG 22:12 LAX 07:12 JFK 10:12
    Do have faith in what you're doing.
    ubao msn snddm index pchome yahoo rakuten mypaper meadowduck bidyahoo youbao zxmzxm asda bnvcg cvbfg dfscv mmhjk xxddc yybgb zznbn ccubao uaitu acv GXCV ET GDG YH FG BCVB FJFH CBRE CBC GDG ET54 WRWR RWER WREW WRWER RWER SDG EW SF DSFSF fbbs ubao fhd dfg ewr dg df ewwr ewwr et ruyut utut dfg fgd gdfgt etg dfgt dfgd ert4 gd fgg wr 235 wer3 we vsdf sdf gdf ert xcv sdf rwer hfd dfg cvb rwf afb dfh jgh bmn lgh rty gfds cxv xcv xcs vdas fdf fgd cv sdf tert sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf sdf shasha9178 shasha9178 shasha9178 shasha9178 shasha9178 liflif2 liflif2 liflif2 liflif2 liflif2 liblib3 liblib3 liblib3 liblib3 liblib3 zhazha444 zhazha444 zhazha444 zhazha444 zhazha444 dende5 dende denden denden2 denden21 fenfen9 fenf619 fen619 fenfe9 fe619 sdf sdf sdf sdf sdf zhazh90 zhazh0 zhaa50 zha90 zh590 zho zhoz zhozh zhozho zhozho2 lislis lls95 lili95 lils5 liss9 sdf0ty987 sdft876 sdft9876 sdf09876 sd0t9876 sdf0ty98 sdf0976 sdf0ty986 sdf0ty96 sdf0t76 sdf0876 df0ty98 sf0t876 sd0ty76 sdy76 sdf76 sdf0t76 sdf0ty9 sdf0ty98 sdf0ty987 sdf0ty98 sdf6676 sdf876 sd876 sd876 sdf6 sdf6 sdf9876 sdf0t sdf06 sdf0ty9776 sdf0ty9776 sdf0ty76 sdf8876 sdf0t sd6 sdf06 s688876 sd688 sdf86