let uid = 0 export default function Dep () { this.id = uid++ // 订阅调度中心的watch数组 this.subs = [] } // 当前watch实例 Dep.target = null // 添加订阅者 Dep.prototype.addSub = function (sub) { this.subs.push(sub) } // 移除订阅者 Dep.prototype.removeSub = function (sub) { this.subs.$remove(sub) } // 订阅 Dep.prototype.depend = function () { // Dep.target.addDep(this) => this.addSub(Dep.target) => this.subs.push(Dep.target) Dep.target.addDep(this) } // 通知更新 Dep.prototype.notify = function () { // stablize the subscriber list first var subs = this.subs.slice() for (var i = 0, l = subs.length; i < l; i++) { // subs[i].update() => watch.update() subs[i].update() } }
订阅者的实现
export default function Watcher (vm, expOrFn, cb, options) { // mix in options if (options) { extend(this, options) } var isFn = typeof expOrFn === 'function' this.vm = vm // vm 的 _watchers 包含了所有 watch vm._watchers.push(this) this.expression = expOrFn this.cb = cb this.id = ++uid // uid for batching this.active = true this.dirty = this.lazy // for lazy watchers // deps 一个 watch 实例可以对应多个 dep this.deps = [] this.newDeps = [] this.depIds = Object.create(null) this.newDepIds = null this.prevError = null // for async error stacks // parse expression for getter/setter if (isFn) { this.getter = expOrFn this.setter = undefined } else { warn('vue-lite only supports watching functions.') } this.value = this.lazy ? undefined : this.get() this.queued = this.shallow = false } Watcher.prototype.get = function () { this.beforeGet() var scope = this.scope || this.vm var value try { // 执行 expOrFn,此时会触发 getter => dep.depend() 将watch实例添加到对应 obj[key] 的 dep value = this.getter.call(scope, scope) } if (this.deep) { // 深度watch // 触发每个key的getter watch实例将对应多个dep traverse(value) } // ... this.afterGet() return value } // 触发getter,实现订阅 Watcher.prototype.beforeGet = function () { Dep.target = this this.newDepIds = Object.create(null) this.newDeps.length = 0 } // 添加订阅 Watcher.prototype.addDep = function (dep) { var id = dep.id if (!this.newDepIds[id]) { // 将新出现的dep添加到newDeps中 this.newDepIds[id] = true this.newDeps.push(dep) // 如果已在调度中心,不再重复添加 if (!this.depIds[id]) { // 将watch添加到调度中心的数组中 dep.addSub(this) } } } Watcher.prototype.afterGet = function () { // 切除key的getter联系 Dep.target = null var i = this.deps.length while (i--) { var dep = this.deps[i] if (!this.newDepIds[dep.id]) { // 移除不在expOrFn表达式中关联的dep中watch的订阅 dep.removeSub(this) } } this.depIds = this.newDepIds var tmp = this.deps this.deps = this.newDeps // TODO: 既然newDeps最终会被置空,这边赋值的意义在于? this.newDeps = tmp } // 订阅中心通知消息更新 Watcher.prototype.update = function (shallow) { if (this.lazy) { this.dirty = true } else if (this.sync || !config.async) { this.run() } else { // if queued, only overwrite shallow with non-shallow, // but not the other way around. this.shallow = this.queued ? shallow ? this.shallow : false : !!shallow this.queued = true // record before-push error stack in debug mode /* istanbul ignore if */ if (process.env.NODE_ENV !== 'production' && config.debug) { this.prevError = new Error('[vue] async stack trace') } // 添加到待执行池 pushWatcher(this) } } // 执行更新回调 Watcher.prototype.run = function () { if (this.active) { var value = this.get() if ( ((isObject(value) || this.deep) && !this.shallow) ) { // set new value var oldValue = this.value this.value = value var prevError = this.prevError // ... this.cb.call(this.vm, value, oldValue) } this.queued = this.shallow = false } } Watcher.prototype.depend = function () { var i = this.deps.length while (i--) { this.deps[i].depend() } }
wtach回调执行队列