vue源码分析(十四)核心函数之Watcher
我们打开文件 src/core/observer/watcher.js
。
由于文件代码量过多,我们一一来看,就不一次性帖出来了, Watcher
类主要有如下方法:
constructor
初始化构造函数
get
计算getter
addDep
添加依赖项
cleanupDeps
清理依赖项
update
依赖项更改时调用
run
调用处理函数
evaluate
重新计算值,这只适用于懒惰的观察者
depend
调用Dep的depend函数
teardown
从所有依赖项的订阅服务器列表中移除
我们接下来看几个主要的,简单的我们就略过了:
constructor
constructor (
vm: Component,
expOrFn: string | Function,
cb: Function,
options?: ?Object,
isRenderWatcher?: boolean
) {
this.vm = vm
if (isRenderWatcher) {
vm._watcher = this
}
vm._watchers.push(this)
// 省略部分代码...
// 表达式是否是函数
if (typeof expOrFn === 'function') {
this.getter = expOrFn
} else {
this.getter = parsePath(expOrFn)
if (!this.getter) {
this.getter = noop
process.env.NODE_ENV !== 'production' && warn(
`Failed watching path: "${expOrFn}" ` +
'Watcher only accepts simple dot-delimited paths. ' +
'For full control, use a function instead.',
vm
)
}
}
this.value = this.lazy
? undefined
: this.get()
}
可以看到有对 expOrFn
参数进行类型判断,因为他可能有两种类型 expOrFn: string | Function
字符串和函数。
接下来如果 this.lazy
为真就给value赋值为 'undefined',否则就调用get
函数进行处理。
get
/**
* Evaluate the getter, and re-collect dependencies.
*/
get () {
//入栈操作
pushTarget(this)
let value
const vm = this.vm
try {
// 调用 'constructor '处理好的getter函数
value = this.getter.call(vm, vm)
} catch (e) {
if (this.user) {
handleError(e, vm, `getter for watcher "${this.expression}"`)
} else {
throw e
}
} finally {
// "touch" every property so they are all tracked as
// dependencies for deep watching
// 如果'deep'为真,就对value进行一个深度监听。
if (this.deep) {
traverse(value)
}
//出栈操作
popTarget()
// 清理依赖项
this.cleanupDeps()
}
return value
}
可以看到首先进行了一个 入栈操作pushTarget(this)
,然后调用 constructor
里面处理好的 getter
函数,完成之后判断 deep
是否 为真,就对value进行一个深度监听。紧接着就是出栈操作。
最后 调用 this.cleanupDeps()
清理依赖项 。
update
/**
* Subscriber interface.
* Will be called when a dependency changes.
*/
update () {
/* istanbul ignore else */
if (this.lazy) {
this.dirty = true
} else if (this.sync) {
this.run()
} else {
queueWatcher(this)
}
}
1、如果 lazy
属性为真就把 dirty
标识为真。
2、如果 sync
属性为真,就调用run
方法。
3、否则就调用 queueWatcher
函数,把this推入到列队里面。
run
/**
* Scheduler job interface.
* Will be called by the scheduler.
*/
run () {
if (this.active) {
const value = this.get()
if (
value !== this.value ||
// Deep watchers and watchers on Object/Arrays should fire even
// when the value is the same, because the value may
// have mutated.
isObject(value) ||
this.deep
) {
// set new value
const oldValue = this.value
this.value = value
if (this.user) {
try {
this.cb.call(this.vm, value, oldValue)
} catch (e) {
handleError(e, this.vm, `callback for watcher "${this.expression}"`)
}
} else {
this.cb.call(this.vm, value, oldValue)
}
}
}
}
首先判断 active
是否为真,默认就是 true
,如果是false的话,那就是移除了监听器,或者组件被移除了(调用了destroy
生命周期)。
(active=false代表已被销毁),调用
unwatcher
和触发destroy
都会销毁active
紧接着调用了get
方法,获取最新的value值,然后判断最新的值是否和旧值相等,或者最新的值是object
对象,或者存在deep
选项。
最后调用 cb
函数(一般是用户自定义hanle方法,或者vue自带的一个空函数) 处理。