Mobx 源码分析 - 第一阶段汇总
当我们写
age = observable.box(12)
的时候,写@observable age = 12
的时候,写age = observable(12)
的时候,mobx
做了什么?不知道有多少人仔细研究过,没研究也不要紧,这篇文章就是带你去了解,mobx
具体做了什么?
api/observable.ts 文件
observable.box
observable
上绑定了许多属性,比如常用的 box
、map
和 array
。当我们调用 observable.box
的时候,mobx
会首先判断当前调用方式,如果当前的调用方式会 decorator
调用,则直接报错。
if (arguments.length > 2) incorrectlyUsedAsDecorator("box")
为什么 mobx
可以通过参数个数就能判断出来当前是否为 decorator
调用?那是因为如果通过装饰器调用,会往函数内传入 3 个参数,所以这边通过判断参数个数就可以确定当前是否为 decorator
调用。
相信大家都知道 box
方法还有第二个参数 (不仅仅只是 box
有),这个参数的作用主要用以判断用哪一个 enhancer
和 name
的值。
最后返回 ObservableValue
实例。
new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)
@observable
调用 observable
时候,等于调用 createObservable
。
const observable = createObservable
createObservable
接收 3 个参数,内部会对第二个参数进行判断,如果为 string
,则调用 deepDecorator
函数。
observable()
如果传入的参数为已监听对象,则直接返回;如果不是基本数据类型,则根据参数类型调用不同的包装方法,比如对于 array
调用 observable.array
。如果是 NaN
,直接返回。如果是基本数据类型,提醒用户使用 observable.box
方法。
我们已经知道 mobx
对于我们的代码会做两件不同的事,一种调用 deepDecorator
函数,一种实例化 ObservableValue
。
注意,这里我们只针对于传入的值为
number
类型讨论,不同类型有不同的实现方式
observable.box
实例化 ObservableValue
,ObservableValue
类继承 Atom
类,ObservableValue
内部重写了 set
和 get
方法。
当访问实例时,会向全局发出 reportObserved
事件,并把当前实例存到 derivation.newObserving
中,以便数据发生更改,通知 derivation
。在这里,实例为被观察者,derivation
为观察者。
修改实例值时,会开启事务处理,并向所有的观察者推送此次事件,推送完成后结束事务处理。
究竟 mobx
是如何更新依赖关系?我们以 autorun
举例。
autorun(()=>{
console.log(age.get())
})
2
3
当我们调用 autorun
时候,会在全局状态中增加当前实例,也就是当前的 derivation
,autorun
参数执行时,会把 age
的值,也就是 ObservableValue
实例,推入到当前的 derivation
属性中,derivation
会用 diffValue
来刷新当前依赖关系,保持依赖最新。
@observable
调用 createDecoratorForEnhancer
返回值,在原型上添加 __mobxDecorators
对象,此对象的每一个属性 ( 比方说 @observable age,这里面的属性就是 age ) 都会存放一些关键信息,并劫持属性的 get
与 set
方法。
target.__mobxDecorators[prop] = {
prop,
propertyCreator,
descriptor,
decoratorTarget: target,
decoratorArguments
}
2
3
4
5
6
7
当访问属性,会在原型上添加 __mobxDidRunLazyInitializers
和 $mobx
。$mobx
内存放 ObservableObjectAdministration
实例,并在 $mobx.values
对应的每一个属性存放 ObservableValue
实例。
const observable = (adm.values[propName] = new ObservableValue(
newValue,
enhancer,
`${adm.name}.${propName}`,
false
))
2
3
4
5
6
并对于属性的访问和读取会再次劫持,每当访问,都会调用原型上 $mobx
中 read
和 write
方法。read
和 write
方法所做的事与 observable.box
内部 get
和 set
做的事情一样。