• 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相关订阅(还没完全理解作用)。

  • 相关阅读:
    Katalon系列十九:元素相同或无法定位时的定位技巧
    Katalon系列十八:用例变量&用例间调用
    读《单核工作法》
    Redis 的主从同步(复制)
    Yii2 框架整体结构
    redis 是如何做持久化的
    php yii 查看帮助时会调用具体脚本类的析构函数
    Redis 底层数据结构介绍
    Redis 的常用命令
    Yii2 框架跑脚本时内存泄漏问题分析
  • 原文地址:https://www.cnblogs.com/cqhaibin/p/5658873.html
Copyright © 2020-2023  润新知