const obj = observable({ a: "a", b: "b" }) autorun(() => { console.log(obj.a) }) obj.b = "1" // 不触发回调 obj.a = "2" // 触发回调,打印出 "2"
obj.b没有出现在autorun的回调中,无论怎么修改都不会触发回调,obj.a的修改就会触发回调, mobx是怎样在不通过参数传递(指定)的情况下,能够智能实现收集函数中出现的参数的监听的
- 首先要明确的两点
- 只有回调函数中出现的对象的改变才能触发回调函数
- 要想改变对象触发回调,该对象必须被observable修饰
- mobx怎么知道,或者说“监听“哪些对象的改变可以触发回调
奥秘就在autorun
let autorun = function (handler) {
collectHandlerStart(handler);
handler();
collectHandlerEnd();
};
autorun函数在调用的时候会执行一次回调函数,这也是唯一一次搜集回调的机会
为了简单起见,我们在全局定义一个栈stack,用来保存当前最新的handler,而collectHandlerStart要做的就是将回调压栈
const collectHandlerStart = function (fn) {
stack.push(fn);
};
按照autorun的执行顺序,将回调压栈后,回调收集只完成了一半
最重要的就是还要将收集到的回调绑定在指定的对象上,这里指定的对象是指出现在回调里的对象属性
可是怎样才能知道哪些对象属性出现在一个函数的代码块内呢?执行该函数即可
因为在执行过程中肯定会触发该对象的get访问器属性
- 将回调绑定在出现过在回调中的对象属性上
const dependenceManager = new WeakMap(); get: function (target, key, receiver) { const fn = stack.slice(-1)[0]; if (fn) { dependenceManager.set(target, { ...dependenceManager.get(target), [key]: fn }); } if (typeof target[key] === 'object' && target[key] !== null) { return new Proxy(target[key], handler); } return Reflect.get(target, key, receiver); },
使用proxy可以很轻易的拦截get
将刚才压栈的函数“借用”,现在还不能真正弹出栈他,定义一个WeakMap()用来存储 {“对象” : “值”} 这样的数据结构再合适不过了
判断一下如果fn不为空,说明现在还在handler收集阶段(正在运行autorun),而不是平时的get调用时期
我不清楚真正的mobx内部的唯一标识符是怎么生成的,所以我使用WeakMap,将对象(内存地址总是唯一的)作为唯一标识符,与其对应的回调函数绑定起来
- 如何在修改时触发回调
很容易想到搜集是通过get,那么修改肯定是set了
set: function (target, key, value, receiver) { target[key] = value; trigger(target, key, value); } const trigger = function (target, key, value,) { const mapValue = dependenceManager.get(target); mapValue[key] && mapValue[key](); };
直接用当前的对象最为WeakMap的Key值取出对应的回调函数,然后执行
运行一下文章开头的代码看看效果
在初始化打印a之后,修改b,a,则只有修改a能触发回调
修改一下autorun为
autorun(() => { console.log(obj.b); console.log(obj.a); });
打印结果:
初始化打印了b,a,且修改b触发回调,a还是a,再修改a触发回调,b,a都已改变
- 结束收集
回到autorun函数,在第一次执行了回调函数之后,完成了搜集工作,此时出栈全局stack中的handler
const collectHandlerEnd = function () {
stack.pop();
};
这样,在以后触发get属性时,由于栈为空,就不会再进行handler绑定
到此一个乞丐版mobx便完成了
thx
Check 1this website to learn how to get free diamonds on cooking fever
u3iauds11
Cooking Fever is a whole lot more fun when you have unlimited free gems.If you enjoy mobile games like this you should check out this site
Incredible story there. What occurred after? Take care! Kalina Coop Jentoft