knockout原始碼分析之訂閱

小龍女先生發表於2016-07-10

一、主類關係圖

knockout原始碼分析之訂閱

二、類職責

2.1、observable(普通監控物件類)

observable(他其是一個function)的內部實現:
1.首先宣告一個名為observable的fn(這個可以說是一個類)
2.增加一個ko惟一的latestValue(最新值)屬性來儲存形參傳入的值
3.如果支援原生__proto__屬性就利用hasOwnProperty來判斷屬性是否存在的方式來繼承,判斷__proto__程式碼(在utils類中)

var canSetPrototype = ({ __proto__: [] } instanceof Array);

4.ko.subscribable的fn屬性的init方法對observable進行初始化(主要增加訂閱、釋出相關屬性)
5.observable再繼承observabelFn相關屬性和方法(observabelFn包含觀察、值變化前、值變化後的執行策略)
// Define prototype for observables
var observableFn = {
    'equalityComparer': valuesArePrimitiveAndEqual,
    peek: function() { return this[observableLatestValue]; },
    valueHasMutated: function () { this['notifySubscribers'](this[observableLatestValue]); },
    valueWillMutate: function () { this['notifySubscribers'](this[observableLatestValue], 'beforeChange'); }
};
6.返回observable方法的實現(如果傳入引數就是設定,無參則是獲取)
7、此類還提供了hasPrototype(判斷指定例項是否擁有此屬性)、isObservable(判斷指定例項是否為監控物件)、isWriteableObservable(是否為可寫的監控物件)。

2.2、observableArray(陣列監控物件類)

1.先執行ko.observable方法,讓其物件變為一個可監控的類(名為result);
2.然後擴充套件ko.observableArray中的fn物件(ko.observabelArray的fn重寫了陣列相關的操作方法,如remove、push等)
3.通過extends擴充套件一個方法(trackArrayChanages,詳細介紹見2.5)
4.返回擴充套件好的result物件。

ko.observableArray = function (initialValues) {
    initialValues = initialValues || [];

    if (typeof initialValues != 'object' || !('length' in initialValues))
        throw new Error("The argument passed when initializing an observable array must be an array, or null, or undefined.");

    var result = ko.observable(initialValues);
    ko.utils.setPrototypeOfOrExtend(result, ko.observableArray['fn']);
    return result.extend({'trackArrayChanges':true});
};

2.3、subscribable(訂閱物件類)

1.實現訂閱、釋出的功能模組,對observable、observableArray來說是必不可少的基類
2.這裡有一個subscrible方法,用於對監控物件變化的訂閱介面,開發則可以用此繼切入點

subscribe: function (callback, callbackTarget, event) {
        var self = this;

        event = event || defaultEvent;
        var boundCallback = callbackTarget ? callback.bind(callbackTarget) : callback;

        var subscription = new ko.subscription(self, boundCallback, function () {
            ko.utils.arrayRemoveItem(self._subscriptions[event], subscription);
            if (self.afterSubscriptionRemove)
                self.afterSubscriptionRemove(event);
        });

        if (self.beforeSubscriptionAdd)
            self.beforeSubscriptionAdd(event);

        if (!self._subscriptions[event])
            self._subscriptions[event] = [];
        self._subscriptions[event].push(subscription);

        return subscription;
    }

3.extend:此方法用於新增extends方法加入的擴充套件類(如observableArray.changeTracking擴充套件類)
4.extend擴充套件的方法,會在監控物件註冊後立即執行,傳入引數為target(當前物件)、options(extend呼叫時傳入的引數)
5.extend就是安裝擴充套件的方法,他會立即執行擴充套件中的程式碼。

2.4、extends(擴充套件監控物件類)

1.ko預設的擴充套件集合
2.提供一個applyExtenders方法來安裝擴充套件

function applyExtenders(requestedExtenders) {
    var target = this;
    if (requestedExtenders) {
        ko.utils.objectForEach(requestedExtenders, function(key, value) {
            var extenderHandler = ko.extenders[key];
            if (typeof extenderHandler == 'function') {
                target = extenderHandler(target, value) || target;
            }
        });
    }
    return target;
}

2.5、observableArray.changeTracking(擴充套件監控物件的一個具體實現)

1.此擴充套件主要實現對陣列變化的監控,然後計算陣列的差異,以及觸發相關的訂閱事件
2.cacheDiffForKnownOperation:快取對陣列的操作,以備差異比較
3.beforeSubscriptionAdd、afterSubscriptionRemove相關訂閱(還沒完全理解作用)。

相關文章