mobx.box

用来包裹原始值类型的可观测包装

  1. const x = observable.box(3)
  1. 新建new ObservableValue管理value=3
  2. enhancer默认为deep=true的deepEnhancer 深度遍历构造可观察
  3. ObservableValue包裹3后,控制包裹层的行为,定义get set行为
  4. get执行时,广播到上层自己是个可观察的数据,需要被收集,然后返回具体值
  5. set执行时,如果有拦截器,值不合法则放弃更新,更新后,查看新值是否需要遍历构造观察模型,防止3 => {xxx: 3}
  6. setNewVal_执行具体赋值工作,唤醒监听器handler执行
  7. intercept_注册拦截器,对值校验
  8. toJSON访问一次get()

mobx.array

包装数组 支撑某些工具方法具备可观察特点
proxy拦截一些操作,包装处理
values用于存放数据,任何操作都是在values上替换元素 包括splice,pop等
访问一些不影响原数组的api时,转化为正常数组,再进行操作,比如map filter等

  1. const a = observable.array([])
  1. 新建new ObservableArrayAdministration 是数组可观察
  2. intercept拦截器,interceptors= []
  3. observe 注册监听器 changeListeners = []
  4. getArrayLength获取数组长度 广播上报自己是可观察对象且被当前外层观察
  5. setArrayLength,如果长度新>旧,补充空元素,如果旧>新 删除多余元素,调用的方法是spliceWithArray
  6. spliceWithArray_,判断传入的index合法性,且可以添加新成员替换,如果有拦截器且操作非法,类似splice,返回空数组,表示无操作成功元素
  7. updateArrayLength_, spliceItemsIntoValues找准位置插入
  8. notifyArraySplice_通知有变
  9. new Proxy管控真实数组的get set 数组被proxy处理后,访问下标都是字符串形式 xx[1] => proxy[‘1’]
  10. get处理,如果访问的是length,adm.getArrayLength_
  11. 拦截原生方法,改造成有广播功能的方法 比如splice, shift, pop, push等
  12. set处理,实际执行adm.set_,进行拦截器预先处理,然后广播变化,且enhancer来处理,决定是否需要对新增或者改变的元素深度遍历监听 看起来不能直接 xx = []这样清空了 新增了clear方法完成这个工作
  13. 不对原数组进行改变操作的就不去动它 让它访问原始值 concat,flat, includes, indexOf, join, lastIndexOf,slice, toString, toLocaleString,every,filter等

mobx.map

  1. const x = mobx.observable.map({ a: 3 })
  1. new ObservableMap() 构建观察管理员 观察目标数据
  2. adm的merge处理数据初始化,再调用set方法逐个key-value设置
  3. 询问是否有拦截器,拦截器处理
  4. 如果之前存在key,则updateValue,否则新增addValue
  5. 开启事务 操作结束前不通知任何观察着
  6. new ObservableValue(value)观察key对应的value
  7. 查看是否有监听者 广播通知变更
  8. 如果是updateVlaue_,设置新的key对应的value,且通知监听者
  9. 包装keys,values, entries等api的可监听性

mobx.set

类似map

  1. mobx.set(a, "x", 0)
  1. new ObservableSet()
  2. 包装keys, entries,delete,add等api

mobx.object

  1. mobx.object({x: 1})
  1. 创建一个被观察的对象的管理员 adm = new ObservableObjectAdministration()
  2. getOwnPropertyDescriptors获取对象的所有自身属性
  3. 开启proxy,代理target {x: 1}
  4. 开启batch,调用adm的extend通过defineProperty扩展,后续会发出新增属性通知
  5. 对象的属性扩展中 改写get,使之成computed包裹类型
  6. 改写set,使之能触发action,
  7. 继续扩展 遍历value是否需要深度包装

mobx.observe_

注册监听

  1. const x = observable.box(3)
  2. m.observe(x, func)
  1. 获取observable对象的adm,可观察对象的管理者 ObservableValue, ObservableArrayAdministration,ObservableMap,ObservableSet,ObservableObjectAdminisration
  2. 调用注册的observe_方法添加监听器changeListeners = []
  3. 变更通知,去除changeListeners中的handler执行

批量处理的含义

  1. const x = observable.box(3)
  2. const y = observable.box(2)
  3. const z = computed(function () {
  4. return x.get() * y.get()
  5. })
  6. startBatch() // 开始批量处理 进入了computed包裹方法范围
  7. this.value_ = this.computeValue_(false) // 这边回执行到x.get y.get
  8. endBatch()
  9. // this.value_ = this.computeValue_(false) // 这边回执行到x.get y.get
  10. reportObserved(this) // 都会收集监听者 computed
  11. if (shouldCompute(this)) {
  12. let prevTrackingContext = globalState.trackingContext
  13. if (this.keepAlive_ && !prevTrackingContext) globalState.trackingContext = this
  14. if (this.trackAndCompute()) propagateChangeConfirmed(this)
  15. globalState.trackingContext = prevTrackingContext
  16. }
  17. // 如果是这种深度嵌套是怎么处理呢
  18. const x = observable.box(3)
  19. const y = observable.box(2)
  20. const z = computed(function () {
  21. return x.get() * y.get()
  22. })
  23. const e = computed(function () {
  24. return z.get()
  25. })

Observable

observable.box

  1. const x = observable.box(3)
  2. // 1. observableFactories.box
  3. box<T = any>(value?: T, options?: CreateObservableOptions): IObservableValue<T> {
  4. const o = asCreateObservableOptions(options)
  5. return new ObservableValue(value, getEnhancerFromOptions(o), o.name, true, o.equals)
  6. },
  7. // 1.1 asCreateObservableOptions(options) // options = undefined
  8. //options 是否deep监听 是否用proxy
  9. {
  10. deep: true,
  11. name: undefined,
  12. defaultDecorator: undefined,
  13. proxy: true
  14. }
  15. // 2. 对原始值的处理
  16. ObservableValue(value) //包裹原始值
  17. // 3. 初始值 enhancer(value, undefined, name_) 完成简单的注册
  18. export function deepEnhancer(v, _, name) {
  19. // it is an observable already, done
  20. if (isObservable(v)) return v // new ObservableValue命中 是已观测的
  21. ...
  22. }
  23. // 4. 与computed合作
  24. // const x = observable.box(3)
  25. const z = computed(function () {
  26. return x.get() * 2
  27. })
  28. // 5. 建立一个computed观察对象
  29. const opts: IComputedValueOptions<any> = isPlainObject(arg2) ? arg2 : {}
  30. // get = computed包裹的那个方法
  31. opts.get = arg1
  32. opts.name ||= arg1.name || "" /* for generated name */
  33. return new ComputedValue(opts) // 返回一个ComputedValue包裹的值
  34. // 6. new ComputedValue主要属性
  35. this.derivation = options.get!
  36. this.setter_
  37. this.get()
  38. this.set
  39. // 7. z.get()
  40. // 7.1 globalState.inBatch === 0非批处理 this.observers_.size === 0无观察者就开始计算
  41. this.value_ = this.computeValue_(false) // track = false 无跟踪
  42. // 7.2 传入的上下文context可以作为scope取参数
  43. res = this.derivation.call(this.scope_) // this.derivation = 包裹的方法
  44. // 9. 执行过程中 触发到了x 收集x的依赖集合数组 x.get() 上报被监听了
  45. reportObserved(this) // this = box(3) = ObservableValue
  46. // 10. box(3)的监听者收集为空 且inBatch > 0(在监听者中执行) 就收集当前监听者
  47. observable.observers_.size === 0 && globalState.inBatch > 0
  48. // 11. 开始收集
  49. queueForUnobservation(observable)
  50. // 12. 当前这个box(3) 被监听了 自己在执行中 标记自己是被监听中的收集状态 在computed的执行范围中
  51. export function queueForUnobservation(observable: IObservable) {
  52. if (observable.isPendingUnobservation_ === false) {
  53. // invariant(observable._observers.length === 0, "INTERNAL ERROR, should only queue for unobservation unobserved observables");
  54. observable.isPendingUnobservation_ = true
  55. globalState.pendingUnobservations.push(observable) // 全局pengding
  56. }
  57. }
  58. // 13. 上报结束后 需要endBatch computed的
  59. computed去拿值都能拿到最新的 并没有去设定这个监听 box没有收集computed 要收集的是reaction reaction中可能包含computed


observable.object({x: 1})

observable.object({x_ 1}).png

observable.object({x_ 1}).png