简单一点,即收集完订阅者们的密探 A 只管发布消息,共产党 B 以及更多的共产党只管订阅消息并进行对应的 update 操作,每个模块确保其独立性,实现高内聚低耦合这两大原则。
废话不多说,我们接下来直接开始讲 vue 是如何做的消息封装的
2.1、Dep
Dep,全名 Dependency,从名字我们也能大概看出 Dep 类是用来做依赖收集的,具体怎么收集呢。我们直接看源码
let uid = 0
export default class Dep {
static target: ?Watcher;
id: number;
subs: Array<Watcher>;
constructor () {
// 用来给每个订阅者 Watcher 做唯一标识符,防止重复收集
this.id = uid++
// 定义subs数组,用来做依赖收集(收集所有的订阅者 Watcher)
this.subs = []
}
// 收集订阅者
addSub (sub: Watcher) {
this.subs.push(sub)
}
depend () {
if (Dep.target) {
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++) {
subs[i].update()
}
}
}
// the current target watcher being evaluated.
// this is globally unique because there could be only one
// watcher being evaluated at any time.
Dep.target = null
代码很简短,但它做的事情却很重要
- 定义subs数组,用来收集订阅者Watcher
- 当劫持到数据变更的时候,通知订阅者Watcher进行update操作
源码中,还抛出了两个方法用来操作 Dep.target ,具体如下
// 定义收集目标栈
const targetStack = []
export function pushTarget (_target: Watcher) {
if (Dep.target) targetStack.push(Dep.target)
// 改变目标指向
Dep.target = _target
}
export function popTarget () {
// 删除当前目标,重算指向
Dep.target = targetStack.pop()
}
2.2、 Watcher
Watcher 意为观察者,它负责做的事情就是订阅 Dep ,当Dep 发出消息传递(notify)的时候,所以订阅着 Dep 的 Watchers 会进行自己的 update 操作。废话不多说,直接看源码就知道了。
export default class Watcher {
vm: Component;
expression: string;
cb: Function;
constructor (
vm: Component,
expOrFn: string | Function,
cb: Function,
options?: Object
) {
this.vm = vm
vm._watchers.push(this)
this.cb = cb
// parse expression for getter
if (typeof expOrFn === 'function') {
this.getter = expOrFn
} else {
// 解析表达式
this.getter = parsePath(expOrFn)
if (!this.getter) {
this.getter = function () {}
}
}
this.value = this.get()
}
get () {
// 将目标收集到目标栈
pushTarget(this)
const vm = this.vm
let value = this.getter.call(vm, vm)
// 删除目标
popTarget()
return value
}
// 订阅 Dep,同时让 Dep 知道自己订阅着它
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)
}
}
}
// 订阅者'消费'动作,当接收到变更时则会执行
update () {
this.run()
}
run () {
const value = this.get()
const oldValue = this.value
this.value = value
this.cb.call(this.vm, value, oldValue)
}
}
内容版权声明:除非注明,否则皆为本站原创文章。
