簡單講講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)
})
相關文章
相關標籤/搜索