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 表明是当前哪个 Watcherif (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 idsubs: 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.idif (!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