# Watcher
- Vue会为当前实例创建一个renderWathcer挂载在
vm._watcher上。 - 非
renderWacher- 会将每个创建的Wathcer添加到
vm._watchers数组中。 computed创建的Watcherlazy属性设置为true。以来值触发更新时watcher.update(),会将Watcher的dirty值设置为true。当computed触发了 了它的computedGetter时就会通过watcher.evaluate()更新watcher.value的值- 普通Watcher触发更新都会通过queueWatcher(this)进入更新队列中,等待在异步任务中去触发
watcher.update() -> watcher.run()。
- 会将每个创建的Wathcer添加到
export default class Watcher {
vm: Component;
expression: string;
cb: Function;
id: number;
deep: boolean;
user: boolean;
lazy: boolean;
sync: boolean;
dirty: boolean;
active: boolean;
deps: Array<Dep>;
newDeps: Array<Dep>;
depIds: SimpleSet;
newDepIds: SimpleSet;
before: ?: Function;
getter: Function;
value: any
constructor (
vm: Component,
expOrFn: string | Function,
cb: Function,
options?: Object,
isRenderWatcher?: boolean // 用来更新渲染 dom 的 watcher
) {
this.vm = vm;
if (isRenderWatcher) {
vm._watcher = this
}
vm._watchers.push(this)
if (options) {
this.deep = !!options.deep
this.user = !!options.user
this.lazy = !!options.lazy // watcher 值是否缓存
this.sync = !!options.sync
// before钩子函数
this.before = options.before
} else {
this.deep = this.user = this.lazy = this.sync = false
}
this.cb = cb
this.id = ++uid // watcher id 自增
this.active = true
this.dirty = this.lazy
this.deps = []
this.newDeps = []
this.depIds = new Set()
this.newDepIds = new Set()
this.expression = process.env.NODE_ENV !== 'production' ? exporFn.toString() : ''
// expOrFn 可以是个函数 返回 this.data ...
if (typeof expOrFn === 'function') {
this.getter = expOrFn
} else {
this.getter = parsePath(expOrFn)
if (!this.getter) {
this.getter = noop
// 省略错误处理
// throw new Error(/* error */)
}
}
this.value = this.lazy ? undefined : this.get()
}
// 执行 this.getter,获取需要监听的属性的值 ,并重新收集依赖
// 为什么要重新更新收集依赖
// 因为触发说明数据被更新了 但是被更新的数据虽然已经经过 observe,但去没有进行依赖收集。
// 在更新页面时,会重新执行一次 render 函数,执行期间会触发读取操作,这时候进行依赖收集
get () {
pushTarget(this) // 就是进行 Dep.target = this 的操作,方便依赖收集
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm)
} catch (e) {
// doSomething...
} finally {
if (this.deep) {
traverse(value)
}
// 清除Dep.target
popTarget()
this.cleanupDeps()
}
return value
}
// observe 中收集依赖 自身添加 dep 只是为了方便 teardown 时方便删除对应的 watcher
addDep (dep: Dep) {
// 去重,dep 已经存在则不重复添加
const id = dep.id
if (!this.newDepIds.has(id)) {
// 缓存
this.newDepsIds.add(id)
this.newDeps.push(dep)
// 避免在 dep 中添加重复wathcer
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}
// 去除已经不依赖的 Dep
cleanupDeps () {
let i = this.deps.length
while (i --) {
const dep = this.deps[i]
// 如果 dep 不存在 newDepsIds 中 则在对应的 dep 里删除当前 Watcher
if (!this.newDepIds.has(dep.id)) {
// dep 里的 remove 应该会将对应的 id 和 dep 在当前的 deps 与 depIDS ..中移除自己
dep.removeSub(this)
}
}
let tmp = this.depIds
this.depIds = this.newDepIds
this.newDepIds = tmp
this.newDepIds.clear()
tmp = this.deps
this.deps = this.newDeps
this.newDeps = tmp
this.newDeps.length = 0
}
// 根据 options 来决定
update () {
if (this.lazy) { // computed 将 dirty 设置为 true 当 dirty 为 true 时会重新获取值
this.dirty = true
} else if (this.sync) { // 同步执行 一般为了性能不会设置 sync
this.run()
} else {
// 放进 watcher 的异步队列里
queueWatcher(this)
}
}
// 非 computed 其实是通过调用此方法 来获取最新值
run () {
if (this.active) {
const value = this.get()
if (
value !== this.value ||
isObject(value) ||
this.deep
) {
const oldValue = this.value
this.value = value
// 如果是用户定义的 wathcer 则传入 newVal 和 oldVal
if (this.user) {
try {
this.cb.call(this.vm, value, oldValue)
} catch (e) {
// doSomething...
}
} else {
this.cb.call(this.vm, value, oldValue)
}
}
}
}
// 当 Watcher 的 dirty 为 true 时 会调用该方法
evaluate () {
this.value = this.get()
this.dirty = false
}
// 向所有的 deps 中添加当前 watcher
depend () {
let i = this.deps.length
while (i--) {
this.deps[i].depend()
}
}
// 将当前 watcher 从所有 deps 中移除
teardown () {
if (this.active) {
if (!this.vm._isBeingDestroyed) {
remove(this.vm._watchers, this)
}
}
let i = this.deps.length
while (i--) {
this.deps[i].removeSub(this)
}
this.active = false
}
}