數(shù)據(jù)綁定模塊 最核心的三個(gè)類: Observer,Watcher,Dep
observer是Vue核心中最重要的一個(gè)模塊(個(gè)人認(rèn)為),能夠?qū)崿F(xiàn)視圖與數(shù)據(jù)的響應(yīng)式更新,底層全憑observer的支持。
observer模塊在Vue項(xiàng)目中的代碼位置是src/core/observer,模塊共分為這幾個(gè)部分:
- Observer: 數(shù)據(jù)的觀察者,讓數(shù)據(jù)對(duì)象的讀寫操作都處于自己的監(jiān)管之下
- Watcher: 數(shù)據(jù)的訂閱者,數(shù)據(jù)的變化會(huì)通知到Watcher,然后由Watcher進(jìn)行相應(yīng)的操作,例如更新視圖
- Dep: Observer與Watcher的紐帶,當(dāng)數(shù)據(jù)變化時(shí),會(huì)被Observer觀察到,然后由Dep通知到Watcher
示意圖如下:
Observer
Observer類定義在src/core/observer/index.js中,先來看一下Observer的構(gòu)造函數(shù)
constructor (value: any) {
this.value = value
this.dep = new Dep()
this.vmCount = 0
def(value, '__ob__', this)
if (Array.isArray(value)) {
const augment = hasProto
? protoAugment
: copyAugment
augment(value, arrayMethods, arrayKeys)
this.observeArray(value)
} else {
this.walk(value)
}
}
value是需要被觀察的數(shù)據(jù)對(duì)象,在構(gòu)造函數(shù)中,會(huì)給value增加ob屬性,作為數(shù)據(jù)已經(jīng)被Observer觀察的標(biāo)志。如果value是數(shù)組,就使用observeArray遍歷value,對(duì)value中每一個(gè)元素調(diào)用observe分別進(jìn)行觀察。如果value是對(duì)象,則使用walk遍歷value上每個(gè)key,對(duì)每個(gè)key調(diào)用defineReactive來獲得該key的set/get控制權(quán)。
解釋下上面用到的幾個(gè)函數(shù)的功能:
- observeArray: 遍歷數(shù)組,對(duì)數(shù)組的每個(gè)元素調(diào)用observe
- observe: 檢查對(duì)象上是否有ob屬性,如果存在,則表明該對(duì)象已經(jīng)處于Observer的觀察中,如果不存在,則new Observer來觀察對(duì)象(其實(shí)還有一些判斷邏輯,為了便于理解就不贅述了)
- walk: 遍歷對(duì)象的每個(gè)key,對(duì)對(duì)象上每個(gè)key的數(shù)據(jù)調(diào)用defineReactive
- defineReactive: 通過Object.defineProperty設(shè)置對(duì)象的key屬性,使得能夠捕獲到該屬性值的set/get動(dòng)作。一般是由Watcher的實(shí)例對(duì)象進(jìn)行g(shù)et操作,此時(shí)Watcher的實(shí)例對(duì)象將被自動(dòng)添加到Dep實(shí)例的依賴數(shù)組中,在外部操作觸發(fā)了set時(shí),將通過Dep實(shí)例的notify來通知所有依賴的watcher進(jìn)行更新。
如果不太理解上面的文字描述可以看一下圖:
Dep
Dep是Observer與Watcher之間的紐帶,也可以認(rèn)為Dep是服務(wù)于Observer的訂閱系統(tǒng)。Watcher訂閱某個(gè)Observer的Dep,當(dāng)Observer觀察的數(shù)據(jù)發(fā)生變化時(shí),通過Dep通知各個(gè)已經(jīng)訂閱的Watcher。
Dep提供了幾個(gè)接口:
- addSub: 接收的參數(shù)為Watcher實(shí)例,并把Watcher實(shí)例存入記錄依賴的數(shù)組中
- removeSub: 與addSub對(duì)應(yīng),作用是將Watcher實(shí)例從記錄依賴的數(shù)組中移除
- depend: Dep.target上存放這當(dāng)前需要操作的Watcher實(shí)例,調(diào)用depend會(huì)調(diào)用該Watcher實(shí)例的addDep方法,addDep的功能可以看下面對(duì)Watcher的介紹
- notify: 通知依賴數(shù)組中所有的watcher進(jìn)行更新操作
Watcher
Watcher是用來訂閱數(shù)據(jù)的變化的并執(zhí)行相應(yīng)操作(例如更新視圖)的。Watcher的構(gòu)造器函數(shù)定義如下:
constructor (vm, expOrFn, cb, options) {
this.vm = vm
vm._watchers.push(this)
// options
if (options) {
this.deep = !!options.deep
this.user = !!options.user
this.lazy = !!options.lazy
this.sync = !!options.sync
} else {
this.deep = this.user = this.lazy = this.sync = false
}
this.cb = cb
this.id = ++uid // uid for batching
this.active = true
this.dirty = this.lazy // for lazy watchers
this.deps = []
this.newDeps = []
this.depIds = new Set()
this.newDepIds = new Set()
this.expression = process.env.NODE_ENV !== 'production'
? expOrFn.toString()
: ''
if (typeof expOrFn === 'function') {
this.getter = expOrFn
} else {
this.getter = parsePath(expOrFn)
if (!this.getter) {
this.getter = function () {}
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()
}
參數(shù)中,vm表示組件實(shí)例,expOrFn表示要訂閱的數(shù)據(jù)字段(字符串表示,例如a.b.c)或是一個(gè)要執(zhí)行的函數(shù),cb表示watcher運(yùn)行后的回調(diào)函數(shù),options是選項(xiàng)對(duì)象,包含deep、user、lazy等配置。
watcher實(shí)例上有這些方法:
- get: 將Dep.target設(shè)置為當(dāng)前watcher實(shí)例,在內(nèi)部調(diào)用this.getter,如果此時(shí)某個(gè)被Observer觀察的數(shù)據(jù)對(duì)象被取值了,那么當(dāng)前watcher實(shí)例將會(huì)自動(dòng)訂閱數(shù)據(jù)對(duì)象的Dep實(shí)例
- addDep: 接收參數(shù)dep(Dep實(shí)例),讓當(dāng)前watcher訂閱dep
- cleanupDeps: 清除newDepIds和newDep上記錄的對(duì)dep的訂閱信息
- update: 立刻運(yùn)行watcher或者將watcher加入隊(duì)列中等待統(tǒng)一flush
- run: 運(yùn)行watcher,調(diào)用this.get()求值,然后觸發(fā)回調(diào)
- evaluate: 調(diào)用this.get()求值
- depend: 遍歷this.deps,讓當(dāng)前watcher實(shí)例訂閱所有dep
- teardown: 去除當(dāng)前watcher實(shí)例所有的訂閱
observe(value):
function observe (value, asRootData) {
if (!isObject(value)) {
return
}
var ob;
if (hasOwn(value, '__ob__') && value.__ob__ instanceof Observer) {
ob = value.__ob__;
} else if (
observerState.shouldConvert &&
!isServerRendering() &&
(Array.isArray(value) || isPlainObject(value)) &&
Object.isExtensible(value) &&
!value._isVue
) {
ob = new Observer(value);
}
if (asRootData && ob) {
ob.vmCount++;
}
return ob
}
給 value 定義一個(gè) __ob__ 作為 Observer 的 key
value:
__ob__:Observer
key1:
get: function reactiveGetter () {
var value = getter ? getter.call(obj) : val;
if (Dep.target) {
dep.depend();
if (childOb) {
childOb.dep.depend();
}
if (Array.isArray(value)) {
dependArray(value);
}
}
return value
},
set: function reactiveSetter (newVal) {
var value = getter ? getter.call(obj) : val;
/* eslint-disable no-self-compare */
if (newVal === value || (newVal !== newVal && value !== value)) {
return
}
/* eslint-enable no-self-compare */
if (process.env.NODE_ENV !== 'production' && customSetter) {
customSetter();
}
if (setter) {
setter.call(obj, newVal);
} else {
val = newVal;
}
childOb = observe(newVal);
dep.notify();
}
__ob__:
value: value
dep: dep
轉(zhuǎn)載自:https://segmentfault.com/a/1190000008377887