前言
所看的源码版本是:"version": "2.6.14"。
Dep
Dep你可以理解为是一个依赖收集器,用来收集watcher的。它里面代码很简单我们一起看看(src/core/observer/dep.js):
import type Watcher from './watcher'
import { remove } from '../util/index'
import config from '../config'
let uid = 0
/**
* A dep is an observable that can have multiple
* directives subscribing to it.
*/
export default class Dep {
static target: ?Watcher;
id: number;
subs: Array<Watcher>;
constructor () {
this.id = uid++
this.subs = [] // 用来收集watcher
}
// 添加watcher
addSub (sub: Watcher) {
this.subs.push(sub)
}
// 移除watcher
removeSub (sub: Watcher) {
remove(this.subs, sub)
}
// 依赖收集 Dep.target是一个watcher 当前存在的时候就将它放入观察者列表当中
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
// 通知订阅者 做更新操作
notify () {
// stabilize the subscriber list first
const subs = this.subs.slice()
if (process.env.NODE_ENV !== 'production' && !config.async) {
// subs aren't sorted in scheduler if not running async
// we need to sort them now to make sure they fire in correct
// order
subs.sort((a, b) => a.id - b.id)
}
for (let i = 0, l = subs.length; i < l; i++) {
subs[i].update()
}
}
}
// The current target watcher being evaluated.
// This is globally unique because only one watcher
// can be evaluated at a time.
Dep.target = null
const targetStack = []
// 下面主要就是 修改Dep.target的指向
export function pushTarget (target: ?Watcher) {
targetStack.push(target)
Dep.target = target
}
export function popTarget () {
targetStack.pop()
Dep.target = targetStack[targetStack.length - 1]
}
Dep类代码还是比较简单的,主要就是几个关键方法。
Watcher
Watcher是一个观察者,主要工作是当观察到有数据变动时,回去执行传入的回调函数做一些更新操作。
Watcher我觉得源码相对来说还是不太好理解的,我们先看几个主要的代码,先主要理解它是做啥的就行。(src/core/observer/watcher.js)
当数据劫持触发set时,会去触发Watcher 中 update方法:
update () {
/* istanbul ignore else */
if (this.lazy) { // 计算属性watcher处理逻辑
this.dirty = true
} else if (this.sync) { // 设置sync同步会马上执行run 方法
this.run()
} else {
// 加入到异步watcher队列做处理,源码位置src/core/observer/scheduler.js 主要是让其在nextTick去执操作 最后还是要执行watcher.run()方法
queueWatcher(this)
}
}
// run 方法主要执行了get和cb方法
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) {
const info = `callback for watcher "${this.expression}"`
invokeWithErrorHandling(this.cb, this.vm, [value, oldValue], this.vm, info)
} else {
this.cb.call(this.vm, value, oldValue)
}
}
}
}
// get一方面和dep建立联系;其次通过getter获取了值
get () {
pushTarget(this)
let value
const vm = this.vm
try {
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
if (this.deep) {
traverse(value)
}
popTarget()
this.cleanupDeps()
}
return value
}
总结
-
结合之前我们学习的
Observer,我们知道了如何对数据进行劫持,在get的时候我们知道哪些地方使用了数据,set的时候我们知道数据变化了,需要通知那些依赖此数据的地方做更新。 -
对于
get时依赖数据的地方我们把它看作一个watcher,在get数据的时候我们通过dep依赖收集器把这些watcher收集起来放在一个数组里面。 -
当数据变化触发
set时,我们执行dep.notify()去通知watcher做更新操作。