Vue 依赖收集整体流程其实就是一套「订阅者模式」,收集订阅者,把所有需要监听内容数据,全都收集起来。
每个组件实例都对应一个 watcher 实例,它会在组件渲染的过程中把“接触”过的数据 property 记录为依赖。之后当依赖项的 setter 触发时,会通知 watcher,从而使它关联的组件重新渲染。 https://cn.vuejs.org/v2/guide/reactivity.html#%E5%A6%82%E4%BD%95%E8%BF%BD%E8%B8%AA%E5%8F%98%E5%8C%96
var dep = new Dep();
Object.defineProperty(obj, key, {
enumerable: true,
configurable: true,
get: function reactiveGetter () {
// 获取当前监听的值
const value = getter ? getter.call(obj) : val;
// Dep 在上面已经声明;
// Dep.target 表明是当前哪个 Watcher
if (Dep.target) {
dep.depend();// 添加到订阅列表里,方法在 dep.js 文件定义
if (childOb) {
childOb.dep.depend()
if (Array.isArray(value)) {
dependArray(value)
}
}
}
return value
}
})
export default class Dep {
static target: ?Watcher;// 静态属性
id: number;// Dep id
subs: Array<Watcher>;// Watcher 列表
constructor () {
this.id = uid++
this.subs = []
}
addSub (sub: Watcher) {
this.subs.push(sub)
}
removeSub (sub: Watcher) {
remove(this.subs, sub)
}
depend () {
if (Dep.target) {
Dep.target.addDep(this)
}
}
}
export default class Watcher {
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)
}
}
},
get () {
pushTarget(this)
}
}
const targetStack = []
export function pushTarget (target: ?Watcher) {
targetStack.push(target)
Dep.target = target
}
export function popTarget () {
targetStack.pop()
Dep.target = targetStack[targetStack.length - 1]
}
依赖收集的目的为了把 Watcher 收集起来,等触发 getter 的时候,会通知需要更新的 watcher 去执行更新。
推荐阅读
Vue 在挂载数据前都经历了什么?
原创文章,作者:小道研究,如若转载,请注明出处:https://www.sudun.com/ask/34516.html