Vue defineReactive

Vue defineReactive

大致执行过程

依赖收集

  1. initState 时,调用 initPropsinitData 等 init 方法,通过 Observer 添加 getter 和 setter。
  2. Observer 中调用 defineReactive 完成响应式对象初始化。
  3. 在 DefineReactive 中设置 getter,并在 getter 中通过 dep.depend() 收集依赖。

建立观察者

  1. mountComponent 时会建立一个 watcher。
  2. 创建 watcher 时触发 updateComponent,从而触发组件依赖元素的 getter。
  3. 触发各个元素 getter 中的依赖收集。Dep.target 设置为当前 watcher。
  4. Dep.target.addDep 会将各个元素依赖添加到当前 watcher。
  5. Dep.target.addDep 调用时也会调用 dep.addSub 将 watcher 添加到 dep 的观察者列表中。

更新

  1. 当修改值时会触发元素的 setter。
  2. 通过 dep.notify() 通知 watcher。
  3. 在 watcher 的 update 中执行更新方法。

源码:defineReactive

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
/**
* Define a reactive property on an Object.
*/
export function defineReactive (
obj: Object,
key: string,
val: any,
customSetter?: ?Function,
shallow?: boolean
) {
const dep = new Dep()

const property = Object.getOwnPropertyDescriptor(obj, key)
if (property && property.configurable === false) {
return
}

// cater for pre-defined getter/setters
const getter = property && property.get
const setter = property && property.set
if ((!getter || setter) && arguments.length === 2) {
val = obj[key]
}

let childOb = !shallow && observe(val)
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
const value = getter ? getter.call(obj) : val
// Dep.target 在 mountComponent 中设置
if (Dep.target) {
// 收集依赖
dep.depend()
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
},
set: function reactiveSetter (newVal) {
const value = getter ? getter.call(obj) : val
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter()
}
// #7981: for accessor properties without setter
if (getter && !setter) return
if (setter) {
setter.call(obj, newVal)
} else {
val = newVal
}
childOb = !shallow && observe(newVal)
//当设置值时通知 dep
dep.notify()
}
})
}

源码: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
65
66
67
68
69
70
71
72
73
import type Watcher from './watcher'
import { remove } from '../util/index'

let uid = 0

/**
* 定义可观测对象,允许多次订阅
* 是响应式的核心部分
* 在对象 getter 中调用来观测对象元素
* 实际上是对 watcher 的管理
*/
export default class Dep {
static target: ?Watcher;
id: number;
subs: Array<Watcher>;

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

/**
* 在 watcher 中调用了此方法,用来收集订阅者
*
*/
addSub (sub: Watcher) {
// 记录观察者
this.subs.push(sub)
}

removeSub (sub: Watcher) {
remove(this.subs, sub)
}

/**
* 在对象元素的 getter 中调用
* 由于 mountComponent 时添加了 watcher
* 在 Watcher 的 constructor 中:
* 1. 将此 watcher 设置为了 Dep.target,
* 2. 执行表达式,触发表达式依赖元素的 getter
*/
depend () {
if (Dep.target) {
// 添加当前依赖到 watcher
Dep.target.addDep(this)
}
}

notify () {
// stabilize the subscriber list first
const subs = this.subs.slice()
for (let i = 0, l = subs.length; i < l; i++) {
// 设置值时会调用 watcher 的 update,执行 update 策略
subs[i].update()
}
}
}

/**
* target 是当前活动的 watcher
* 在使用中同一时间只有一个 watcher 被使用
*/
Dep.target = null
const targetStack = []

export function pushTarget (_target: ?Watcher) {
if (Dep.target) targetStack.push(Dep.target)
Dep.target = _target
}

export function popTarget () {
Dep.target = targetStack.pop()
}
# vue

评论

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×