# 7. vue响应式原理

# 1. 初始化处理

响应式原理

初始化数据initData时调用obsreve函数。 observe函数主要做了3件事:

  1. 如果不是对象则啥都不做退出。
  2. 对象已经是响应式的了,有__ob__了,直接返回这个依赖收集器。
  3. 对象还不是响应式的,执行new Observer()

Observer中主要做了3件事:

  1. 新建一个new Dep()依赖收集器,定义到obj.__ob__上。
  2. 如果是对数组,修改数组原型,遍历数组,如果不是对象则退出,是对象则继续调用observe
  3. 如果是对象,则对对象遍历将对象中的属性变为响应式的,调用defineReactive

defineReactive主要做了:

  1. 对对象值val继续执行observe
  2. get中进行依赖收集dep.depend()
  3. set中如果添加了新值则执行observe
  4. set中进行派发更新dep.notify()
class Observer {
  constructor (value: any) {
    this.value = value
    this.dep = new Dep()
    this.vmCount = 0
    def(value, '__ob__', this)
    if (Array.isArray(value)) {
      //1. 改变数组原型,对push/pop/unshift/shift/reverse/sort/splice方法做出修改,
      //2. 对数组执行了这7个方法,则更新视图
      //3. 如果执行了push/unshift/splice对数组新增属性,则还要执行observeArray方法,收集依赖。
      	
      this.observeArray(value)//遍历数组,执行observe函数
    } else {
      this.walk(value)//遍历对象对每个值创建依赖收集器收集依赖
    }
  }

  walk (obj: Object) {
    const keys = Object.keys(obj)
    for (let i = 0; i < keys.length; i++) {
      defineReactive(obj, keys[i])
    }
  }

  observeArray (items: Array<any>) {
    for (let i = 0, l = items.length; i < l; i++) {
      observe(items[i])
    }
  }
}

export function observe (value) {
  if (value !== null && typeof value === 'object') {
    return
  }
  let ob
  //如果已经有依赖收集器了(代码省略):直接赋值
  ob = value.__ob__
  //如果没有依赖收集器(代码省略):新建new Dep()
  ob = new Observer(value)
  return ob
}

//定义一个响应式属性在对象上
export function defineReactive (obj,key,val) {
  const dep = new Dep()
  observe(val)
  Object.defineProperty(obj, key, {
    get: function reactiveGetter () {
      dep.depend()
      return value
    },
    set: function reactiveSetter (newVal) {
      if (newVal === val) return
      val = newVal
      observe(newVal)
      dep.notify();
    }
  })
}
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

改写数组原型:

const result = original.apply(this, args)//执行原始的数组方法
let inserted
switch (method) {
  case 'push':
  case 'unshift':
    inserted = args
    break
  case 'splice':
    inserted = args.slice(2)
    break
}
if (inserted) ob.observeArray(inserted)
// notify change
ob.dep.notify()
1
2
3
4
5
6
7
8
9
10
11
12
13
14

# 2. 收集依赖、更新视图

依赖收集 收集依赖流程:

observe -> 
walk -> 
defineReactive -> 
get -> 
dep.depend() -> 
watcher.addDep(new Dep()) -> 
watcher.newDeps.push(dep) -> 
dep.addSub(new Watcher()) -> 
dep.subs.push(watcher)
1
2
3
4
5
6
7
8
9

派发更新 更新视图流程:

set -> 
dep.notify() -> 
subs[i].update() -> 
watcher.run() || queueWatcher(this) -> 
watcher.get() || watcher.cb -> 
watcher.getter() -> 
vm._update() -> 
vm.__patch__()
1
2
3
4
5
6
7
8
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)
  }

  depend () {
    if (Dep.target) {
      Dep.target.addDep(this)
    }
  }

  notify () {
    for (let i = 0, l = subs.length; i < l; i++) {
      subs[i].update()
    }
  }
}

Dep.target = null

//Watcher中使用
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
class Watcher {
  vm: Component;
  cb: Function;
  id: number;
  deps: Array<Dep>;
  newDeps: Array<Dep>;
  depIds: SimpleSet;
  newDepIds: SimpleSet;
  getter: Function;
  value: any;

  constructor (
    vm: Component,
    expOrFn: string | Function,
  ) {
    this.vm = vm
    this.id = ++uid // uid for batching
    this.deps = []
    this.newDeps = []
    this.depIds = new Set()
    this.newDepIds = new Set()
    
	//lifecycle.js中mountComponent定义的的new Watcher()中的updateComponent方法,执行vm._update(vm._render(), hydrating),更新视图
    this.getter = expOrFn
    
    this.value = this.get()
  }
  
  /**
   * Evaluate the getter, and re-collect dependencies.
   */
  get () {
    pushTarget(this)//Dep中定义,Dep.target=this
    let value
    const vm = this.vm
    value = this.getter.call(vm, vm)
    popTarget()
    this.cleanupDeps()//清除收集的依赖
    return value
  }
  
  /**
   * Add a dependency to this directive.
   */
  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 on all deps collected by this watcher.
   */
  depend () {
    let i = this.deps.length
    while (i--) {
      this.deps[i].depend()
    }
  }
}

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
66

# 3. 参考

vue.js源码 - 剖析observer,dep,watch三者关系 如何具体的实现数据双向绑定 (opens new window)