Vue实例化执行顺序

Posted by Youzi on June 16, 2021

Vue实例化执行顺序

响应式系统核心的三大类:

  1. observe:遍历 data 中的属性,使用 Object.definePropertyget/set 方法对其进行数据劫持;
  2. dep:每个属性拥有自己的消息订阅器 dep,用于存放所有订阅了该属性的观察者对象;
  3. watcher:观察者(对象),通过 dep 实现对响应属性的监听,监听到结果后,主动触发自己的回调进行响应。

  4. initProps
  5. initMethods
  6. initData
  7. initComputed
  8. initWatch

initComputed

遍历computed对象,实例化每一个计算属性Watcher

1
2
3
4
5
6
7
8
// key是computed对象的key
// watchers是存放所有计算属性订阅者实例的对象
watchers[key] = new Watcher(
  vm, // 组件实例
  getter || noop, // get函数
  noop,
  { lazy: true } // 标记该watcher是一个计算属性的watcher
)

实例化后,调用defineComputeduserDef是一个函数(或是有get | set两个方法的对象)

1
defineComputed(vm, key, userDef)

Watcher的构造函数,watcher对象是一个观察者,通过实例化dep

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
class Watcher {
  constructor (
    vm: Component,
    expOrFn: string | Function,
    cb: Function,
    options?: ?Object,
    isRenderWatcher?: boolean
  ) {
    if (options) {
      this.lazy = !!options.lazy
    } 
    if (this.computed) {
      this.value = undefined
      // 执行这一句
      this.dep = new Dep()
    } else {
      this.value = this.get()
    }
  }
  // get函数,调用watcher实例的get函数并得到返回值
  get () {
    pushTarget(this)
    let value
    const vm = this.vm
    try {
      value = this.getter.call(vm, vm)
    } catch (e) {
      
    } finally {
      popTarget()
    }
    return value
  }
  // 
  update () {
    if (this.computed) {
      if (this.dep.subs.length === 0) {
        this.dirty = true
      } else {
        this.getAndInvoke(() => {
          this.dep.notify()
        })
      }
    } else if (this.sync) {
      this.run()
    } else {
      queueWatcher(this)
    }
  }
 
  evaluate () {
    if (this.dirty) {
      this.value = this.get()
      this.dirty = false
    }
    return this.value
  }
 
  depend () {
    if (this.dep && Dep.target) {
      this.dep.depend()
    }
  
}

Dep的构造函数

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
export default class Dep {
  static target: ?Watcher;
  subs: Array<Watcher>;
 
  constructor () {
    this.id = uid++
    this.subs = []
  }
 
  addSub (sub: Watcher) {
    this.subs.push(sub)
  }
 
  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }
 
  notify () {
    const subs = this.subs.slice()
    for (let i = 0, l = subs.length; i < l; i++) {
      subs[i].update()
    }
  }
}
 
Dep.target = null