參考資料:
https://blog.csdn.net/qq_37939251/article/details/90683466
https://blog.csdn.net/afk46847/article/details/101509059(主要是這篇)
依賴收集(源碼級(jí)理解)
當(dāng)創(chuàng)建watcher的時(shí)候絮宁,會(huì)觸發(fā)watcher.get方法
watcher.get方法如下
get () {
pushTarget(this)
let value
const vm = this.vm
try {
value = this.getter.call(vm, vm)
} catch (e) {
// 省略...
} finally {
// 省略...
popTarget()
this.cleanupDeps()
}
return value
}
get方法中會(huì)去調(diào)用watcher.getter方法【value = this.getter.call(vm, vm)】
對(duì)于computedWatcher來說是computed中屬性的表達(dá)式
對(duì)于renderWatcher來說watcher.getter方法是updateComponent杈曲,
這個(gè)方法會(huì)生成renderFunction,然后將renderFunction生成vnode
生成vnode的過程中會(huì)獲取data中屬性的值畦徘,進(jìn)而會(huì)觸發(fā)data中數(shù)據(jù)的getter方法禀挫,getter方法會(huì)觸發(fā)依賴收集
dep的depend方法如下:(Dep.target是當(dāng)前的watcher)
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
watcher的addDep方法如下
addDep (dep: Dep) {
const id = dep.id
if (!this.newDepIds.has(id)) {
this.newDepIds.add(id)
this.newDeps.push(dep)
if (!this.depIds.has(id)) {
dep.addSub(this)
}
}
}
addDep方法將當(dāng)前watcher中沒有收集的dep收集到當(dāng)前watcher中【進(jìn)行了去重】旬陡,
因?yàn)閐ep中會(huì)保留上一次依賴的watcher,將上一次沒有的watcher收集到dep中
watcher.cleanupDeps()方法用于設(shè)置deps和newDeps的狀態(tài)
例子
<div>{{a}} {语婴}</div> 對(duì)應(yīng)一個(gè)renderWatcher
data: {
a: 1, -> 對(duì)應(yīng)dep(a)
b: 2 -> 對(duì)應(yīng)dep(b)
}
第一次頁面初始化后,首先是
renderWatcher dep(a) dep(b)
deps newDeps
[] [dep(a), dep(b)] [renderWatcher] [renderWatcher]
然后執(zhí)行了watcher.clearnupDeps
[dep(a), dep(b)] [] [renderWatcher] [renderWatcher]
當(dāng)修改b的值時(shí)候
[[dep(a), dep(b)] [dep(b)] [renderWatcher] [renderWatcher]
執(zhí)行了watcher.clearnupDeps之后
[dep(b)] [] [renderWatcher] [renderWatcher]