依赖收集

Dep这个对象是依赖收集的核心,里面涉及到get/set的依赖收集和派发, Dep要看整个文件,里面的内容都很重要。 回忆一下,在我们执行_init的时候,执行了$mount$mount其实就是执行了mountComponent, 其中的new Watchervm._updateget的时候执行了。而这个get方法中,有两个方法和这里强相关,看代码


  get () {
    // pushTarget将Watcher实例传入,调用的就是Dep里的方法
    pushTarget(this)
    let value
    const vm = this.vm
    try {
      // 核心执行了updateComponent
      value = this.getter.call(vm, vm)
    } catch (e) {
      ...
    } finally {
      ...
      // 执行完成之后弹出
      popTarget()
      // 并且清理了依赖
      this.cleanupDeps()
    }
    return value
  }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20

这里vue将Dep.target指向了watcher, 那么下面的Dep.target.addDep(this)(想想vue之前在observer的get中调用 了dep.depend),其实就是指向了watcheraddDep方法, 那么继续看Watcher.md

let uid = 0

/**
 * A dep is an observable that can have multiple
 * directives subscribing to it.
 */
export default class Dep {
  static target: ?Watcher;
  id: number;
  subs: Array<Watcher>;

  constructor () {
    this.id = uid++
    this.subs = []
  }

  // 收集依赖
  addSub (sub: Watcher) {
    this.subs.push(sub)
  }

  removeSub (sub: Watcher) {
    remove(this.subs, sub)
  }
  // observer中调用了depend方法,注意 Dep.target就是watcher, 
  // 所以这里其实调用的watcher的 addDep方法,并把dep传入
  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }

  notify () {
    // stabilize the subscriber list first
    const subs = this.subs.slice()
    if (process.env.NODE_ENV !== 'production' && !config.async) {
      // subs aren't sorted in scheduler if not running async
      // we need to sort them now to make sure they fire in correct
      // order
      subs.sort((a, b) => a.id - b.id)
    }
    for (let i = 0, l = subs.length; i < l; i++) {
      // 调用每个订阅者的update方法
      subs[i].update()
    }
  }
}

// Dep.target用来存放目前正在使用的watcher
// 全局唯一,并且一次也只能有一个watcher被使用

Dep.target = null
const targetStack = []

// 入栈并将当前 watcher 赋值给了Dep.target
export function pushTarget (target: ?Watcher) {
  targetStack.push(target)
  Dep.target = target
}

export function popTarget () {
  targetStack.pop()
  Dep.target = targetStack[targetStack.length - 1]
}

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
Last Updated: