当对象间存在一对多关系时,则使用观察者模式(Observer Pattern)。 比如,当一个对象被修改时,则会自动通知依赖它的对象。观察者模式属于行为型模式。
模块文件
- index.js
- 主要用于将对象转换为响应式对象(Object.defineProperty)
- Observer、defineReactive
- watcher.js
- 观察者
- dep.js
- 依赖,用来收集观察者
- array.js
- 劫持数组方法,当修改数组时会触发更新
- traverse.js
- 递归对象,进行对象的深度监听,进行依赖收集,用于watch的deep选项为true时,还有createElement中
- scheduler.js
- 这是个负责调度的方法,更合理的执行watcher更新
流程顺序
new Vue()
initRender(vm)
-
initState(vm)
new Observe
new Watcher(vm, expOrFn)
- construction
- 将expOrFn转换为function。expOrFn有可能是表达式,也可能是function
- this.getter = expOrFn;
- this.getter = parsePath(expOrFn);
- Watch.prototype.get()
- pushTarget(this)
- targetStack.push(target);
- Dep.target = target;
- let value = this.getter.call(vm, vm); 触发Object.defineProperty的get方法
- dep.depend(); 收集watcher
- pushTarget(this)
- 将expOrFn转换为function。expOrFn有可能是表达式,也可能是function
- construction
3种watcher
这里的expOrFn传的是updateComponent,包着vm._update
-
vm.patch
createElm()
- createComponent(vnode)
- vnode.data.hook.init()
child.$mount(vm.$mount)
图例
export default {
name: 'app',
components: {
HelloWorld,
HelloWorld1
},
mounted () {
console.log(this)
console.log(this.$data)
// 第一个读取组件内data触发依赖收集的,就是组件的视图template中的渲染
// 一个组件内只存在一个render函数,所以如果在template中使用到的变量,都会收集到render-watcher
console.log(this.test.__ob__.dep.subs[0] === this.a.__ob__.dep.subs[0])
// 这个render-watcher 是同一个wather对象
},
computed: {
testComputed () {
return this.test.msg + 1
},
testComputed2 () {
return this.test.msg + 2
}
},
data () {
return {
test: {
msg: 'Welcome to Your Vue.js App'
},
a: [
1,
2,
3
]
}
}
}
重点关注
- 响应式数据和依赖收集的过程
- 三种watcher的异同
- scheuler调度方法对watcher队列的执行
疑惑点
observer/index.js
// #7981: for accessor properties without setter