vue的computed的get过程代码分析

关于vue的computed执行过程精析

最近由于使用vue比较频繁,所以对computed执行过程比较感兴趣,所以找来vue源码进行分析,希望对大家的学习过程有所帮助。

initComputed和definedComputed所执行的操作

在initComputed的时候会给this._computedWatchers初始化一个{key:new watcher()}

watcher
vue的computed的get过程代码分析

definedComputed的函数中给computed的name定义

Object.defineProperty(target, key, sharedPropertyDefinition);

获取computed的值时

当你使用获取该计算属性值时,会触发该key的get函数,该函数其实就是执行watcher.evaluate()和watcher.depend()最后返回watcher.value

1.其中watcher.evaluate()方法会执行以下函数
vue的computed的get过程代码分析

其实就是执行watcher的get()函数,并赋值给watcher的value

其中watcher的get方法如下
vue的computed的get过程代码分析

可以看到先执行了pushTarget(this)方法,进去看看
vue的computed的get过程代码分析

其中Dep.target=watcher,给target赋值

2.随后调用value = this.getter.call(vm, vm),其实是在调用watcher的getter方法,getter方法
vue的computed的get过程代码分析

就是computed下的函数,这段代码就是执行该函数,并获取值。

3.该方法会触发该函数下的相关data的get方法,首先会获取该value
vue的computed的get过程代码分析

其中Dep.target在initComputed的时候将watcher赋值,该watcher是监听函数的watcher,随后执行dep.depend();方法,该方法如下:

调用该方法前该data的dep为
vue的computed的get过程代码分析

由于Dep.target已经赋值给computed的函数watcher,所以

Dep.target.addDep(this) 就是执行该watcher的addDep(this)方法,其中的this指的是computed所关联的data的Dep,该Dep对象如下所示

.id: 8

.subs: []

addDep方法如下所示:
vue的computed的get过程代码分析

this等于Dep.target指的是computed下的watcher,判断该watcher的newDepIds是否包含该data的id,一开始为false,所以执行:
vue的computed的get过程代码分析

vue的computed的get过程代码分析

接下来执行dep.addSub(this),其中dep指的是相关联data的dep,this指的是Dep.target,即computed的watcher,执行如下方法:

Dep.prototype.addSub = function addSub (sub) {

this.subs.push(sub);

};

vue的computed的get过程代码分析

将相关联data的subs添加该watcher,至此回到相关data的getter方法,此时已经执行完了dep.depend()方法。
vue的computed的get过程代码分析

可以看出,在获取相关联data的value值时会将该watcher加入到该data的dep的subs数组中,并且会给computed下的函数的watcher的这些数据进行赋值,如下所示:

.newDeps: [Dep]

.depIds: Set(0) {}

.newDepIds: Set(1) {6}

执行完成后返回第一个value,如果有多个data则会循环获取多个value,并重复上述操作。最后会执行popTarget(),该函数如下所示:

vue的computed的get过程代码分析

该targetStack数组包含三个watcher
vue的computed的get过程代码分析

最后一个为我们的computed下的函数,如下图:
vue的computed的get过程代码分析

执行targetStack.pop();删除该watcher,执行Dep.target = targetStack[targetStack.length - 1],改变指向,变为data的watcher,不再是computed的watcher。随后执行this.cleanupDeps(),如下所示:
vue的computed的get过程代码分析

此时的this指的是computed下的函数,获取该函数的deps:
vue的computed的get过程代码分析

该函数的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()前:
vue的computed的get过程代码分析

执行cleanupDeps()后:
vue的computed的get过程代码分析

执行完毕返回value:

此时回到:
vue的computed的get过程代码分析

vue的computed的get过程代码分析

将dirty置为false,下次获取如果值没有变化则直接返回

在执行完watcher.evaluate方法后,执行如下方法:
vue的computed的get过程代码分析

此时的Dep.target方法在popTarget 时就已经为data的watcher,该watcher还是computed的函数watcher,只是Dep.target的值发生变化,执行watcher.depend()方法,如下所示:
vue的computed的get过程代码分析

遍历watcher的deps并执行depend方法:
vue的computed的get过程代码分析
vue的computed的get过程代码分析
vue的computed的get过程代码分析

此时的this为dep,由于Dep.target已经发生变化,所以给data的subs添加dep,data下的watcher值变为:

vue的computed的get过程代码分析

循环执行,最后返回
vue的computed的get过程代码分析

总结

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

回到顶部