vue的computed的get过程代码分析
关于vue的computed执行过程精析
最近由于使用vue比较频繁,所以对computed执行过程比较感兴趣,所以找来vue源码进行分析,希望对大家的学习过程有所帮助。
initComputed和definedComputed所执行的操作
在initComputed的时候会给this._computedWatchers初始化一个{key:new watcher()}
watcher
definedComputed的函数中给computed的name定义
Object.defineProperty(target, key, sharedPropertyDefinition);
获取computed的值时
当你使用获取该计算属性值时,会触发该key的get函数,该函数其实就是执行watcher.evaluate()和watcher.depend()最后返回watcher.value
1.其中watcher.evaluate()方法会执行以下函数
其实就是执行watcher的get()函数,并赋值给watcher的value
其中watcher的get方法如下
可以看到先执行了pushTarget(this)方法,进去看看
其中Dep.target=watcher,给target赋值
2.随后调用value = this.getter.call(vm, vm),其实是在调用watcher的getter方法,getter方法
就是computed下的函数,这段代码就是执行该函数,并获取值。
3.该方法会触发该函数下的相关data的get方法,首先会获取该value
其中Dep.target在initComputed的时候将watcher赋值,该watcher是监听函数的watcher,随后执行dep.depend();方法,该方法如下:
调用该方法前该data的dep为
由于Dep.target已经赋值给computed的函数watcher,所以
Dep.target.addDep(this) 就是执行该watcher的addDep(this)方法,其中的this指的是computed所关联的data的Dep,该Dep对象如下所示
.id: 8
.subs: []
addDep方法如下所示:
this等于Dep.target指的是computed下的watcher,判断该watcher的newDepIds是否包含该data的id,一开始为false,所以执行:
接下来执行dep.addSub(this),其中dep指的是相关联data的dep,this指的是Dep.target,即computed的watcher,执行如下方法:
Dep.prototype.addSub = function addSub (sub) {
this.subs.push(sub);
};
将相关联data的subs添加该watcher,至此回到相关data的getter方法,此时已经执行完了dep.depend()方法。
可以看出,在获取相关联data的value值时会将该watcher加入到该data的dep的subs数组中,并且会给computed下的函数的watcher的这些数据进行赋值,如下所示:
.newDeps: [Dep]
.depIds: Set(0) {}
.newDepIds: Set(1) {6}
执行完成后返回第一个value,如果有多个data则会循环获取多个value,并重复上述操作。最后会执行popTarget(),该函数如下所示:
该targetStack数组包含三个watcher
最后一个为我们的computed下的函数,如下图:
执行targetStack.pop();删除该watcher,执行Dep.target = targetStack[targetStack.length - 1],改变指向,变为data的watcher,不再是computed的watcher。随后执行this.cleanupDeps(),如下所示:
此时的this指的是computed下的函数,获取该函数的deps:
该函数的deps长度为0,此时执行
var tmp = this.depIds;
this.depIds = this.newDepIds;
this.newDepIds = tmp;
this.newDepIds.clear();
将该computed下的函数的watcher的depIds赋值,随后执行
tmp = this.deps;
this.deps = this.newDeps;
this.newDeps = tmp;
this.newDeps.length = 0;
将newDeps的值给deps并给自己清空,如下图所示:
执行cleanupDeps()前:
执行cleanupDeps()后:
执行完毕返回value:
此时回到:
将dirty置为false,下次获取如果值没有变化则直接返回
在执行完watcher.evaluate方法后,执行如下方法:
此时的Dep.target方法在popTarget 时就已经为data的watcher,该watcher还是computed的函数watcher,只是Dep.target的值发生变化,执行watcher.depend()方法,如下所示:
遍历watcher的deps并执行depend方法:
此时的this为dep,由于Dep.target已经发生变化,所以给data的subs添加dep,data下的watcher值变为:
循环执行,最后返回
总结
1.初始化 data 和 computed,分别代理其 set 和 get 方法,对 data 中的所有属性生成唯一的 dep 实例
2.对 computed 中的 属性生成唯一的 watcher,并保存在 vm._computedWatchers 中
3.访问计算属性时,设置 Dep.target 指向 计算属性的 watcher,调用该属性具体方法
4.方法中访问 data 的属性,即会调用 data 属性的 get 方法,将 data 属性的 dep 加入到 计算属性的 watcher , 同时该 dep 中的 subs 添加这个 watcher
5.设置 data 的这个属性时,调用该属性代理的 set 方法,触发 dep 的 notify 方法
6.因为时 computed 属性,只是将 watcher 中的 dirty 设置为 true
7.最后,访问计算属性的 get 方法时,得知该属性的 watcher.dirty 为 true,则调用 watcher.evaluate() 方法获取新的值
以上是 vue的computed的get过程代码分析 的全部内容, 来源链接: utcz.com/a/56196.html