第一次浏览源码,可能有了解的不太正确的中央心愿大佬们能帮我纠正。开始看的是6,起初看到observable发现和5的差距还是有一点的,所以在所以“autorun”的局部可能会有6的源码,但差距并不大。
1.mobx的基本概念
Observable 被观察者
Observer 察看
Reaction 响应
var student = mobx.observable({ name: '张三',});mobx.autorun(() => { console.log('张三的名字:', student.name);});
2.mobx的原理
1.在响应式函数中(如以上autorun中通常会拜访一个或多个observable对象),
- 1)autorun首先创立一个Reaction类型的实例对象reaction,通过参数track一个响应式函数的回调函数。
- 2)而后执行reaction.schedule_办法,执行回调函数,回调函数中调用被观察者observable.get办法,触发reportObserved办法。
- 3)reportObserved办法中会将observavle对象收集到globalState.trackingDerivation.newObserving_队列中(globalState.trackingDerivation此时等同于reaction对象)
- 4)解决reaction和observable的依赖关系,遍历reaction.newObserving_属性,在newObserving_队列中的每一个observable.observers_属性中增加以后reaction对象。
2.被观察者observable的value发生变化,调用observable对象set办法,触发propagateChange办法。propagateChange办法中,遍历observable.observers_属性顺次执行reaction.onBecomeStale办法,再次将以上的2)3)4)执行一遍。
3.源码解读–autorun
以下为删减后的代码
3.1 autorun
export function autorun( view: (r: IReactionPublic) => any,// autoruan函数的回调函数 opts: IAutorunOptions = EMPTY_OBJECT): IReactionDisposer { const name: string = "Autorun" const runSync = !opts.scheduler && !opts.delay // 首先创立一个Reaction类型的对象 次要性能是用来管制工作的执行 let reaction = new Reaction( name, function (this: Reaction) { this.track(reactionRunner) }, opts.onError, opts.requiresObservable ) function reactionRunner() { view(reaction) } // view即autorun函数的回调 reaction.schedule_() // 立刻执行一次部署 return reaction.getDisposer_() // 用于在执行期间清理 autorun}
从上边的源码能够看出autorun次要做了一下三个动作
- 1)创立一个Reaction类型的对象 次要性能是用来管制工作的执行
- 2)将view即auto的回调函数,调配给reaction.track
- 3)立刻执行一次部署 ,此时你应该了解文档中所说的“当应用autorun时,所提供的函数总是立刻被触发”
3.2 reaction.schedule_的源码
schedule_() { if (!this.isScheduled_) { this.isScheduled_ = true globalState.pendingReactions.push(this) // 以后的reaction对象入列 runReactions() // 队列中的所有reaction对象执行runReaction_办法 }}function runReactionsHelper() { let remainingReactions = allReactions.splice(0) for (let i = 0, l = remainingReactions.length; i < l; i++) remainingReactions[i].runReaction_()}
schedule_办法做了两件事
- 1)以后的reaction对象入列
- 2)队列中的所有reaction对象执行runReaction_办法
3.3 runReaction_源码
runReaction_() { startBatch() // 开启一层事务 this.isScheduled_ = false if (shouldCompute(this)) {// derivation.dependenciesState_默认为-1 (未跟踪) this.onInvalidate_() } endBatch() // 敞开一层事务 startBatch和endBatch总是成对呈现}
翻看上边的代码能够发现onInvalidate_是在初始化Reaction时传入构造函数的,实际上时调用了reaction.track办法
track(fn: () => void) { startBatch() ... const result = trackDerivedFunction(this, fn, undefined) // 执行工作 更新依赖 ... endBatch()}
3.4 track办法次要是调用了trackDerivedFunction
export function trackDerivedFunction<T>(derivation: IDerivation, f: () => T, context: any) { ... globalState.trackingDerivation = derivation // 将derivation(此处等同于reaction对象)挂载到全局变量 这样其余成员也可拜访此derivation ... // 执行reaction传递的的回调办法,翻看代码能够看出执行的是autoran函数的回调办法 // 回调中个别会调用一或多个observable对象,触发observable.get办法,再触发reportObserved办法 let result = f.call(context) ... globalState.trackingDerivation = prevTracking bindDependencies(derivation) // 更新observable和raction的依赖关系 return result}
执行因为autorun回调用到了student.name变量,这里的"."其实就是get操作;一旦设计到get操作,监督这个name的属性的观察员就会执行reportObserved办法(后边介绍Oobservable时候会重点介绍这里)。
3.5 reportObserved源码
export function reportObserved(observable: IObservable): boolean { ... const derivation = globalState.trackingDerivation if (derivation !== null) { if (derivation.runId_ !== observable.lastAccessedBy_) { // 更被观察者的lastAccessedBy_属性(事务id),这个是为了防止反复操作 observable.lastAccessedBy_ = derivation.runId_ // 更新derivation(此处为reaction)的newObserving属性,将被观察者退出该队列中 // 后续derivation和observable更新依赖关系就靠这个属性 derivation.newObserving_![derivation.unboundDepsCount_++] = observable ... } return true } else if (observable.observers_.size === 0 && globalState.inBatch > 0) { queueForUnobservation(observable) } return false}
上边的代码,咱们次要关注影响derivation的操作
- 1)更新observable的lastAccessedBy_属性(事务id),这个是为了防止反复操作。
- 2)更新derivation(此处为reaction)的newObserving属性,将observable退出该队列中,后续derivation和observable更新依赖关系就靠这个属性
随后autorun的工作执行实现后,derivation就开始着手更新和被观察者observable的依赖关系
3.6 bindDependencies源码
function bindDependencies(derivation: IDerivation) { const prevObserving = derivation.observing_ // derivation.newObserving_为derivation依赖的observable对象的队列 const observing = (derivation.observing_ = derivation.newObserving_!) let lowestNewObservingDerivationState = IDerivationState_.UP_TO_DATE_ // 默认为0 let i0 = 0, l = derivation.unboundDepsCount_ for (let i = 0; i < l; i++) { /** * 以下是一个去重的过程 * observable.diffValue_默认是0 * 循环时候置为1,因为observing为Observable类型的对象数组,所以不同地位上雷同的值的diffValue_都会变成1 * 在遍历到反复项后就不会进入下边的判断,i0就不会++ * 遍历到非反复项(diffValue_为0的项),则间接将此项填充到i0对应的地位上 * 这样数组循环结束,i0即非反复项的数量,observing.length = i0即删除掉了多余项 */ const dep = observing[i] if (dep.diffValue_ === 0) { dep.diffValue_ = 1 if (i0 !== i) observing[i0] = dep i0++ } } observing.length = i0 derivation.newObserving_ = null // newObserving 置空 /** * prevObserving中和observing中存在的均为observable对象 * 此时如果在上边的循环实现后 observing存在的observable对象的diffValue_均为1 * 在prevObserving队列如果是diffValue_依然为0,示意以后derivation曾经不依赖此observable对象 */ l = prevObserving.length while (l--) { const dep = prevObserving[l]; if (dep.diffValue_ === 0) { // 将以后derivation已不再依赖此observable对象,将其从observable.observers_中的deleted掉 removeObserver(dep, derivation) } dep.diffValue_ = 0 // 将prevObserving队列中的observable的diffValue_均置为0 } while (i0--) { const dep = observing[i0] // observing依然为1的阐明此observable对象不在prevObserving队列中 if (dep.diffValue_ === 1) { dep.diffValue_ = 0 // 在observable.observers_中增加以后的derivation对象 addObserver(dep, derivation) } } // 通过以上的3次循环,将derivation.observing更新为最新的依赖(并去重), // 并在曾经不依赖的observable对象的observers_中delete以后的derivation对象 // 在新建设起的依赖的observable对象的observers_中add以后的derivation对象}
响应被观察者observable对象的value发生变化
上边提及,一旦observable的value发生变化,就会触发observable.get办法,而后触发propagateChange办法,propageateChange源码如下
export function propagateChanged(observable: IObservable) { ... observable.observers_.forEach(d => { ... d.onBecomeStale_() ... }) }
observable.observers_存储的是,与observable对象有依赖关系的derivation对象,在propagateChanged办法中,遍历observers_执行derivation对象的onBecomeStale_办法,咱们来看一下onBecomeStale_的源码
3.7 onBecomeStale_的源码
onBecomeStale_() { this.schedule_()}
this.schedule_是不是很相熟,翻一下上边的代码,发现是在autorun函数中创立reaction对像的时候调用了reaction.schedule_()。所以这下明确propagateChanged调用onBecomeStale_是让reaction再次执行一次之前的部署操作(也就是执行autorun的回调,解决依赖关系);
4.接下来开始看observable(被观察者)局部
4.1 observable的别名createObservable
export const observable: IObservableFactory & IObservableFactories & { enhancer: IEnhancer<any> } = createObservable as any // observable的别名createObservable// 将observableFactories的属性复制一份给observableObject.keys(observableFactories).forEach(name => (observable[name] = observableFactories[name]))
- 1)首先 observable 是函数函数同 createObservable。
- 2)observable复制了observableFactories的属性。
function createObservable(v: any, arg2?: any, arg3?: any) { // @observable someProp; if (typeof arguments[1] === "string" || typeof arguments[1] === "symbol") { return deepDecorator.apply(null, arguments as any) } // it is an observable already, done if (isObservable(v)) return v // something that can be converted and mutated? const res = isPlainObject(v) ? observable.object(v, arg2, arg3) : Array.isArray(v) ? observable.array(v, arg2) : isES6Map(v) ? observable.map(v, arg2) : isES6Set(v) ? observable.set(v, arg2) : v // this value could be converted to a new observable data structure, return it if (res !== v) return res}
createObservable办法起到了转发的作用,将传入的对象转发给具体的转换函数。
简略剖析一下具体的转化模式
- 1)arguments[1] === “string” || typeof arguments[1] === “symbol” 采纳的是装璜器@observable,装璜器的参数(target,prop,descriptor)其中arguments[1] 也就是prop为属性名称为字符串类型
- 2)isObservable(v) 曾经转换为察看值了不须要再转换
- 3)observable.object、observable.array、observable.map、observable.set依据传入参数的类型别离调用具体的转换方法
- 4)针对原始类型提醒用户倡议应用observable.box办法
4.2 observable.box
observable.box在文档中是这样介绍的。
observable.box把一般的值转换成可察看的值,如下例。
const name = observable.box("张三");console.log(name.get());// 输入 '张三'name.observe(function(change) { console.log(change.oldValue, "->", change.newValue);});name.set("李四");// 输入 '张三 -> 李四'
observable.box retrun 一个ObservableValue类型的对像。
box<T = any>(value?: T, options?: CreateObservableOptions): IObservableValue<T> { const o = asCreateObservableOptions(options) // 格式化入参 // ObservableValue的领有办法get set observe intercept... return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)},
案例中的“name.set(“李四”)”,就是调用了ObservableValue的set办法。一会再介绍ObservableValue的时候会重点说下。
4.3 外围类 ObservableValue
ObservableValue 继承了 Atom原子类,先梳理一下Atom和ObservableValue和有什么次要能力。
Atom public reportObserved(): boolean { return reportObserved(this)}public reportChanged() { startBatch() propagateChanged(this) endBatch()}ObservableValuepublic set(newValue: T) { const oldValue = this.value newValue = this.prepareNewValue(newValue) as any if (newValue !== globalState.UNCHANGED) { const oldValue = this.value this.value = newValue this.reportChanged() ... }}public get(): T { this.reportObserved() return this.dehanceValue(this.value)}interceptobserve
其中reportObserved、propagateChanged在梳理autorun的时候介绍过。
- 1)reportObserved:调用察看值是用于更新derivation和observable的依赖关系。
- 2)propagateChanged:察看值扭转时,observable对象的observers中存储的derivation,执行onBecomeStale办法,从新执行部署操作。
- 3)Observablevalue的set 批改value同时调用Atom的reportChanged办法触发propagateChanged。
- 4)Observablevalue的get 获取value值的同时调用Atom的reportObserved办法触发reportObserved。
所以上边案例中“name.set(“李四”);”会触发propagateChanged办法,会执行有依赖关系的 derivation 从新执行部署操作
接下来看一下new ObservableValue的时候干了什么?
constructor( value: T, public enhancer: IEnhancer<T>, public name = "ObservableValue@" + getNextId(), notifySpy = true, private equals: IEqualsComparer<any> = comparer.default) { ... this.value = enhancer(value, undefined, name)}
ObservableValue的构造函数中调用enhancer对value进行了解决,enhancer是通过参数是创立ObservableValue类型对象是传递的参数getEnhancerFromOptions(o)。getEnhancerFromOptions默认返回的是deepEnhancer。
function getEnhancerFromOptions(options: CreateObservableOptions): IEnhancer<any> { return options.defaultDecorator ? options.defaultDecorator.enhancer : options.deep === false ? referenceEnhancer : deepEnhancer}
gdeepEnhancer次要内容如下。
export function deepEnhancer(v, _, name) { if (isObservable(v)) return v if (Array.isArray(v)) return observable.array(v, { name }) if (isPlainObject(v)) return observable.object(v, undefined, { name }) if (isES6Map(v)) return observable.map(v, { name }) if (isES6Set(v)) return observable.set(v, { name }) return v}
这个deepEnhancer是不是看上去有点眼生,往上翻一下能够看出他和createObservable 函数十分相似,起到了转发的作用,将传入的对象转发给具体的转换函数。所以要了解observable我门次要就是要理解这些转换函数。接下来咱们次要剖析observable.object。
4.4 observable.object
object<T = any>( props: T, decorators?: { [K in keyof T]: Function }, options?: CreateObservableOptions ): T & IObservableObject { const o = asCreateObservableOptions(options) if (o.proxy === false) { return extendObservable({}, props, decorators, o) as any } else { const defaultDecorator = getDefaultDecoratorFromObjectOptions(o) const base = extendObservable({}, undefined, undefined, o) as any const proxy = createDynamicObservableObject(base) extendObservableObjectWithProperties(proxy, props, decorators, defaultDecorator) return proxy }}
o.proxy为true的时候只是多了一步Proxy,其余的工作根本类似,所以次要关注extendObservable办法就能够了。
extendObservable中调次要用了getDefaultDecoratorFromObjectOptions、asObservableObject、extendObservableObjectWithProperties办法。因为getDefaultDecoratorFromObjectOptions与extendObservableObjectWithProperties有关联,所以先来看asObservableObject,再看另外两个办法。
4.5 extendObservable
export function extendObservable<A extends Object, B extends Object>( target: A, properties?: B, decorators?: { [K in keyof B]?: Function }, options?: CreateObservableOptions): A & B { options = asCreateObservableOptions(options) const defaultDecorator = getDefaultDecoratorFromObjectOptions(options) // 默认返回deepDecorator装璜器 asObservableObject(target, options.name, defaultDecorator.enhancer) // make sure object is observable, even without initial props if (properties) extendObservableObjectWithProperties(target, properties, decorators, defaultDecorator) return target as any}
4.6 asObservableObject
asObservableObject办法:
- 1)创立一个对象amd为ObservableObjectAdministration类的实例。
- 1)amd赋值给target[$mobx]
- 2)返回amd;
export function asObservableObject( target: any, name: PropertyKey = "", defaultEnhancer: IEnhancer<any> = deepEnhancer): ObservableObjectAdministration { const adm = new ObservableObjectAdministration( target, new Map(), stringifyKey(name), defaultEnhancer ) addHiddenProp(target, $mobx, adm) return adm}
4.7 extendObservableObjectWithProperties
extendObservableObjectWithProperties:循环原始对象,对每一个属性值通过都decorator函数解决(decorators办法即通过getDefaultDecoratorFromObjectOptions办法获取的默认为deepDecorator,所以一回间接看deepDecorator)
export function extendObservableObjectWithProperties( target, properties, // 原对象 decorators, defaultDecorator) { startBatch() const keys = ownKeys(properties) // 循环原对象 for (const key of keys) { const descriptor = Object.getOwnPropertyDescriptor(properties, key)! const decorator = decorators && key in decorators ? decorators[key] : descriptor.get ? computedDecorator : defaultDecorator const resultDescriptor = decorator!(target, key, descriptor, true) // 通过装璜器解决 if ( resultDescriptor // otherwise, assume already applied, due to `applyToInstance` ) Object.defineProperty(target, key, resultDescriptor) } endBatch()}
4.8 decorator
decorator默认为deepDecorator,咱们来看一下它都干了什么。
export function createDecoratorForEnhancer(enhancer: IEnhancer<any>): IObservableDecorator { const decorator = createPropDecorator( true, ( target: any, propertyName: PropertyKey, descriptor: BabelDescriptor | undefined, _decoratorTarget, decoratorArgs: any[] ) => { const initialValue = descriptor ? descriptor.initializer ? descriptor.initializer.call(target) : descriptor.value : undefined // 调用target[$mobx].addObservableProp办法 asObservableObject(target).addObservableProp(propertyName, initialValue, enhancer) } ) const res: any = decorator res.enhancer = enhancer return res}
4.9 addObservableProp办法
decorator中调用了target[$mobx].addObservableProp办法
addObservableProp( propName: PropertyKey, newValue, enhancer: IEnhancer<any> = this.defaultEnhancer) { const { target } = this if (hasInterceptors(this)) { // 拦挡解决 const change = interceptChange<IObjectWillChange>(this, { object: this.proxy || target, name: propName, type: "add", newValue }) if (!change) return // 拦截器返回空的时候不须要从新疏忽此次批改。 newValue = (change as any).newValue } // newValue转换成ObservableValue类型 const observable = new ObservableValue( newValue, enhancer, `${this.name}.${stringifyKey(propName)}`, false ) this.values.set(propName, observable) // 存储 newValue = (observable as any).value // generateObservablePropConfig办法返回以下描述符 // { ..., get() { return this[$mobx].read(propName) }, set(v) { this[$mobx].write(propName, v) } } Object.defineProperty(target, propName, generateObservablePropConfig(propName)) // target生成propName属性 const notify = hasListeners(this) const change = { type: "add", object: this.proxy || this.target, name: propName, newValue } this.keysAtom.reportChanged() // this.keysAtom即Atom的实例}
addObservableProp办法
- 1)调用ObservableValue类将newValue转换为可察看值(还记不记得上边ObservableValue调用通过enhancer调用了observable.object办法吗。当初能够看出observable.object办法中在循环对象的属性时又调用了ObservableValue。通过这种递归的形式将对象的属性转换为可察看值)
- 2)将属性key和observable存入target[$mobx].values中
- 3)将原对象属性值增加到target,并通过描述符中get和set都是间接调用this[mobx].read和this[mobx].write办法。
- 4)调用原子类Atom的reportChanged,让依赖此observable对象的derivation从新执行部署操作。
综上extendObservableObjectWithProperties作用即循环原始对象,执行以上4步,实现了将原始对象的属性代理到target上,并将值转换到可察看值,存储在target[$mobx].values中。
4.10 read和write
read(key: PropertyKey) { return this.values.get(key)!.get()} // observable.get办法 public get(): T { this.reportObserved() // Atom下的reportObserved return this.dehanceValue(this.value)}
read办法会依据属性名称从this.values中查找,获取到对应的observable对象再调用observable.get办法触发reportObserved
write(key: PropertyKey, newValue) { const instance = this.target const observable = this.values.get(key) // intercept if (hasInterceptors(this)) { const change = interceptChange<IObjectWillChange>(this, { type: "update", object: this.proxy || instance, name: key, newValue }) if (!change) return newValue = (change as any).newValue } newValue = (observable as any).prepareNewValue(newValue) if (newValue !== globalState.UNCHANGED) { (observable as ObservableValue<any>).setNewValue(newValue) }}// observable.prepareNewValue和observable.setNewValue办法private prepareNewValue(newValue): T | IUNCHANGED { if (hasInterceptors(this)) { const change = interceptChange<IValueWillChange<T>>(this, { object: this, type: "update", newValue }) if (!change) return globalState.UNCHANGED newValue = change.newValue } // apply modifier newValue = this.enhancer(newValue, this.value, this.name) // 调用enhancer转换为可察看模式 return this.equals(this.value, newValue) ? globalState.UNCHANGED : newValue}setNewValue(newValue: T) { const oldValue = this.value this.value = newValue this.reportChanged() if (hasListeners(this)) { notifyListeners(this, { type: "update", object: this, newValue, oldValue }) }}
write办法
- 1)调用observable.prepareNewValue办法将新的value进行转换
- 2)调用observable.setNewValue从新批改值
- 3)触发reportChanged办法。
4.11 综上总结
var student = mobx.observable({ name: '张三',});
mobx通过observable办法用target代理了传入的对象,赋值给student。
因而student的构造应该如下
在调用student.name时候触发会调用get=>read=>observableValue.get=>reportObserved
批改的时候 set=>write=>observableValue.setNewValue=>reportChanged
当初根本能够了解observable是autoruan之间的关系了。