简单一点,即收集完订阅者们的密探 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) } }
内容版权声明:除非注明,否则皆为本站原创文章。