简单讲讲mobx的observable和autoRun

今天想简单聊聊mobx的observable和autoRun函数。不了解es6的proxy和reflect的伙伴,须要先看看这方面的知识点。es6

一、observable
observable的做用是使一个普通的对象,变得可观察。也就是说当一个对象变得可观察了以后,当你改变对象里的一个值的时候,就会去触发对应的有这个引用的autoRun函数。
下面来看看observable的简单实现,这里不考虑对象的嵌套。就假设它只有一层。方便理解概念。函数

var globalID = 0
function observable(obj) {
    var oID = ++globalID
    return new Proxy(obj, {
        get: function (target, key, receiver) {
            collect.startCollect(oID + '' +key)
            return Reflect.get(target, key, receiver)
        },
        set: function (target, key, value, receiver) {
            Reflect.set(target, key, value, receiver)
            collection[oID + '' + key] && collection[oID + '' + key].forEach(c => {
                c()
            });
        }
    })
}

observable的解释在此:引用阮一峰的es6教程里的话
Proxy 能够理解成,在目标对象以前架设一层“拦截”,外界对该对象的访问,都必须先经过这层拦截,所以提供了一种机制,能够对外界的访问进行过滤和改写。Proxy 这个词的原意是代理,用在这里表示由它来“代理”某些操做,能够译为“代理器”。
这里用Proxy是由于当你在可观察对象上加入新的属性时,就不会像Object.defineProperty那样新的属性无法监听了。代理

像上面代码那样,我们就成功的拦截了一个对象的getter和setter了。
每次当你obj.a或者obj.b的时候都会进入get方法。我们在返回obj.a,以前都会去收集依赖。至于到底要不要收集依赖,我这里是由collect.startCollect去判断的。
每当你obj.a = 'balabala'的时候,我们也拦截了set方法。在写入值的以后,就要搞事情了,偷偷地去把收集来的依赖相应的依赖,给所有执行一遍(若是确实有的话)。code

二、autoRun
一旦任何值发生了修改,就去执行传入autoRun的方法。对象

function autorun(handler) {
    collect.begin(handler)
    handler()
    collect.end()
}

有点简单粗暴,是否是。开始收集依赖了,我先发个信号。而后把autoRun里的handler给执行一遍。最后,打声招呼:小朋友你已经兑过奖了,回家吧。执行collect.end()。教程

三、collect
看了上面两个,内心在想那个collect究竟是个什么鬼?get

var collection = {}
var collect = {
    begin: function(handler) {
        collection.handler = handler
        collection.now = true
    },
    startCollect: function(oIDKey) {
        if (collection.now) {
            if (collection[oIDKey]) {
                collection[oIDKey].push(collection.handler)
            } else {
                collection[oIDKey] = [collection.handler]
            }
        }
    },
    end: function() {
        collection.now = false
    }
}

这里的collection我也就写在全局了,简单粗暴。
在autoRun里,咱们先begin,我把handler赋给了collection.handler,嗯简单粗暴。而且把collection.now设为true,表示须要收集依赖了。
而后执行handler(),就会到get里去执行collect.startCollect。
当startCollect的时候,开始干正经活了,先判断一下是否是now。前面咱们劫持了getter,若是不判断collection.now,那么collect.startCollect(oID + '' +key)老是会执行。那就出大事情了。以后,我们就能够放心的去收集handler了。
完事以后吧collection.now设为false。要否则你往往obj.a取值的时候都会反复的收集依赖。io

好了,我想mobx的思路大概是这样的。这是个人理解,有心的同窗帮我纠纠错,蟹蟹~console

最后放上完整的本人的(cuo)dai照ma。function

var globalID = 0
function observable(obj) {
    var oID = ++globalID
    return new Proxy(obj, {
        get: function (target, key, receiver) {
            collect.startCollect(oID + '' +key)
            return Reflect.get(target, key, receiver)
        },
        set: function (target, key, value, receiver) {
            Reflect.set(target, key, value, receiver)
            collection[oID + '' + key] && collection[oID + '' + key].forEach(c => {
                c()
            });
        }
    })
}
var collection = {}
var collect = {
    begin: function(handler) {
        collection.handler = handler
        collection.now = true
    },
    startCollect: function(oIDKey) {
        if (collection.now) {
            if (collection[oIDKey]) {
                collection[oIDKey].push(collection.handler)
            } else {
                collection[oIDKey] = [collection.handler]
            }
        }
    },
    end: function() {
        collection.now = false
    }
}

function autorun(handler) {
    collect.begin(handler)
    handler()
    collect.end()
}

var obj = observable({
    a: 1,
    b: 2
})

autorun(() => {
    console.log('obj.a test1', obj.a)
})
autorun(() => {
    console.log('obj.a test2', obj.a)
})
相关文章
相关标签/搜索