Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

如何自己实现一个 mobx - 原理解析 #12

Open
ckinmind opened this issue Nov 2, 2017 · 0 comments
Open

如何自己实现一个 mobx - 原理解析 #12

ckinmind opened this issue Nov 2, 2017 · 0 comments

Comments

@ckinmind
Copy link
Owner

ckinmind commented Nov 2, 2017

参考资料

要点

  • mobx最最核心是两个功能
    • Observable ,用来包装一个属性为 被观察者
    • autorun ,用来包装一个方法为 观察者
  • autorun 是个神奇的函数,被他包装过的方法,就会变为观察者函数,并且这里有一个很重要的特性,这个函数只会观察自己依赖到的设为 observable 的值
  • 那如何实现依赖收集呢
    • 引申出一个很简单的管理类,我们叫做 dependenceManager,这个工具类中管理了一个依赖的 map,结构是一个全局唯一的 ID 和 对应的监听的函数的数组
    • 这个全局唯一的 ID 实际上代表的就是各个被设置为 observable 的属性值,是 Observable 类的一个属性 obID
    • 当一个被 observable 包装的属性值发生 set 行为的时候,就会触发 dependenceManager.trigger(obID); 从而触发遍历对应的监听函数列表,并且执行,这就是 autorun 的基本原理
  • 那这个依赖的map 是如何收集上来的呢
    • 也是 dependenceManager 的操作
    • 这里 dependenceManager 标记现在开始收集依赖,然后执行 handler 函数,执行结束之后,标记当前收集结束
  • 每个被 observable 过的值在 get 的时候都会判断当前是否正在收集依赖,如果是的话,就会把这个值 和 当前正在收集依赖的 handler 关联起来存储在 dependenceManager 中
  • 整个 s-mobx 核心的原理
    • observable 包装原生值,get 钩子收集依赖,set 钩子触发改变
    • autorun 包装观察者函数,在包装时会提前执行一次,并且触发其中涉及到的 observable 值的 get 钩子收集依赖,将当前的观察者函数对应到每个 observable 值上
  • Observable
    • 包装对象值的 Observable ,核心原理是 Object.defineProperty ,给被包装的属性套上 get 和 set 的钩子,在 get 中响应依赖收集,在 set 中触发监听函数。
    • 数组的包装稍微麻烦,在 s-mobx 中使用 Proxy 来包装,但是兼容性不是很好,在 mobx 中,作者自己模拟了一个数组对象的操作,然后包装在原生数组上
    • 另外对于 Object 对象,为其进行了递归包装,每一级 Object 都绑定了一个 observable
  • observer
    • 给 react 组件的 prototype 做了一次 mixin,为其加入了一个 autorun,autorun的作用就是绑定组件 render 方法和其依赖的值的观察关系。当依赖的值发生变化的时候会触发 autorun 的参数 handler,handler中会强制执行 render() 方法和 forceUpdate()
  • decorator
    • decorator 的实现其实很简单,不过有些坑需要规避,例如 在 decorator 中出现的target,是class 的prototype,而不是class的实例。但是在 return 出来的 descriptor 中,set 和 get 钩子中的this,则是 class 的实例。在实现一些复杂逻辑的时候要注意一下这个点
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant