computed 只会在值用到的时候才会执行函数函数
下文会以此做为依据进行讲解ui
class Foo{
@computed get age() { return expr; } // 推荐用法
}
复制代码
经过调用 createPropDecorator
方法给原型对象建立一个不可枚举的 __mobxDecorators
属性对象,age
会做为属性对象的 key
存在,此方法会返回一个描述符。this
// 添加 __mobxDecorators 属性
const inheritedDecorators = target.__mobxDecorators
addHiddenProp(target, "__mobxDecorators", { ...inheritedDecorators })
// 描述符
{
configurable: true,
enumerable: enumerable,
get() {
initializeInstance(this)
return this[prop]
},
set(value) {
initializeInstance(this)
this[prop] = value
}
}
复制代码
咱们发现这里劫持了属性的 get
和 set
操做,每当执行 get
和 set
操做以前,都会先执行 initializeInstance
。spa
判断实例上 __mobxDidRunLazyInitializers
是否为 true
,若是是则表明对象已经处于可监听状态。不然取原型上的 __mobxDecorators
对象,并遍历此对象的每个 propertyCreator
方法,也就是以前 createPropDecorator
方法的第二个参数。propertyCreator
方法内部把描述符上 get
和 set
与 decoratorArgs[0]
当作 defineComputedProperty
第三个参数传递进去。code
const { get, set } = descriptor
const options = decoratorArgs[0] || {}
defineComputedProperty(instance, propertyName, { get, set, ...options })
复制代码
const adm = asObservableObject(target)
options.name = `${adm.name}.${propName}`
options.context = target
adm.values[propName] = new ComputedValue(options)
Object.defineProperty(target, propName, generateComputedPropConfig(propName))
复制代码
asObservableObject
主要做用为在实例上新增不可枚举的 $mobx
属性,age
会做为属性的 key
存在,属性值为 ObservableObjectAdministration
实例。server
修改 adm.values[propName]
为 ComputedValue
的实例,实例上新增不可枚举的 age
属性,并劫持 get
和 set
,每当访问或设置 age
属性时,其实是访问 $mobx
原型上的 read
和 write
。对象
function generateComputedPropConfig(propName){
return {
get() {
return getAdministrationForComputedPropOwner(this).read(this, propName)
},
set(v) {
getAdministrationForComputedPropOwner(this).write(this, propName, v)
}
}
}
function getAdministrationForComputedPropOwner(owner) {
const adm = owner.$mobx
if (!adm) {
initializeInstance(owner)
return owner.$mobx
}
return adm
}
复制代码
前文说过,访问 age
其实是访问 $mobx
上的 read
,而 read
又返回 values.age
值,也就是至关于访问 ComputedValue
实例的 get
方法。总结下,访问 age
至关于访问 ComputedValue
实例的 get
方法。队列
若是当前不处于事务处理,又没有观察者且 keepAlive
为 false
状态,则开启事务处理,并执行 age
函数,并把返回值保存在 value
中,并结束事务处理。事务
if (globalState.inBatch === 0 && this.observers.length === 0 && !this.keepAlive) {
// NOT_TRACKING
if (shouldCompute(this)) {
this.warnAboutUntrackedRead();
startBatch(); // See perf test 'computed memoization'
this.value = this.computeValue(false);
endBatch();
}
}
复制代码
若是当前处于事务处理或有观察者或 keepAlive
为 true
,则调用 reportObserved
,在正在跟踪的 derivation
中加入当前实例,并设置实例已处于监听状态;若是当前实例没有观察者且当前处于事务中,则把当前实例放入到队列中,等待移除监听状态。执行 age
函数,并刷新监听对象依赖关系,把 age
函数执行结果返回出去,并用此值与旧值进行比对,若是不一致,则使用新值,并改变内部状态。ip
function computeValue(track){
...
res = trackDerivedFunction(this, this.derivation, this.scope)
...
}
复制代码