欢迎加入QQ讨论群258996829
麦子学院 头像
苹果6袋
6
麦子学院

源码讲解knockout依赖属性

发布时间:2016-07-28 20:10  回复:0  查看:2587   最后回复:2016-07-28 20:10  

knockout依赖属性是什么?也许看了教程还是迷迷糊糊,这里就给大家用源码来一个knockout学习教程吧,希望大家能够弄懂knockout依赖属性

 

一、序列图

源码讲解knockout依赖属性

一、主要代码文件

 

1dependentObservable.js:主要包含ko.computed相关方法的处理
2dependencyDetection.js:主要包含依赖的监控上下文对象。

三、主要逻辑

 

1、首先为某个属性定义 一个computed对象,如下源码:

 

var vModel = function(){

        this.fName = ko.observable('fName'),

        this.lName= ko.observable('lName'),

        this.name= ko.computed(function () { //监控依赖对象

            return this.fName() + '-' + this.lName();

        },this);

    };

 

2、当代码在执行ko.computed方法,求值方法被作为参数传入,并赋值给optionsread属性
3、创建一个state字面量对象,其中包含readwrite属性,如下代码:

 

var state = {

        latestValue: undefined,

        isStale: true,

        isBeingEvaluated: false,

        suppressDisposalUntilDisposeWhenReturnsFalse: false,

        isDisposed: false,

        pure: false,

        isSleeping: false,

        readFunction: options["read"],

        evaluatorFunctionTarget: evaluatorFunctionTarget || options["owner"],

        disposeWhenNodeIsRemoved: options["disposeWhenNodeIsRemoved"] || options.disposeWhenNodeIsRemoved || null,

        disposeWhen: options["disposeWhen"] || options.disposeWhen,

        domNodeDisposalCallback: null,

        dependencyTracking: {},

        dependenciesCount: 0,

        evaluationTimeoutInstance: null

    };

4、生成computedObservable对象(function),然后将state附加到_state属性上,则扩展为发布/订阅对象。
5、扩展computedFn所有方法和属性到computedObservable对象上

// Inherit from 'subscribable'

    if (!ko.utils.canSetPrototype) {

        // 'subscribable' won't be on the prototype chain unless we put it there directly

        ko.utils.extend(computedObservable, ko.subscribable['fn']);

    }

    ko.subscribable['fn'].init(computedObservable); //执行发布/订阅对象的init方法,用于初始化发布/订阅对象。

 

    // Inherit from 'computed'

    ko.utils.setPrototypeOfOrExtend(computedObservable, computedFn);

6、然后执行computedObservableevaluateImmediate方法,此方法中最重的三点:
   6.1、在evaluateImmediate_CallReadWithDependencyDetection方法中,创建了依赖监控对象,并添加到依赖监控上下文中

var isInitial = state.pure ? undefined : !state.dependenciesCount,   // If we're evaluating when there are no previous dependencies, it must be the first time

            dependencyDetectionContext = {

                computedObservable: computedObservable,

                disposalCandidates: state.dependencyTracking,

                disposalCount: state.dependenciesCount

            };

 

        ko.dependencyDetection.begin({

            callbackTarget: dependencyDetectionContext,

            callback: computedBeginDependencyDetectionCallback,

            computed: computedObservable,

            isInitial: isInitial

        });

    6.2、然后调用evaluateImmediate_CallReadThenEndDependencyDetection方法,参数传递的state(在ko.computed方法中定义的)、dependencyDetectionContext(依赖监控对象)
    6.3、其中用到了try catch finall方式,确保ko.dependencyDetection.end方法的执行

try {

            var readFunction = state.readFunction;

            return state.evaluatorFunctionTarget ? readFunction.call(state.evaluatorFunctionTarget) : readFunction();

        } finally {

            ko.dependencyDetection.end();

 

            // For each subscription no longer being used, remove it from the active subscriptions list and dispose it

            if (dependencyDetectionContext.disposalCount && !state.isSleeping) {

                ko.utils.objectForEach(dependencyDetectionContext.disposalCandidates, computedDisposeDependencyCallback);

            }

 

            state.isStale = false;

        }

7、在执行ko.computedreadFunction方法时,其中就执行了ko.observable方法(执行的是read),这时就会去调用ko.dependencyDetection.registerDependency方法(参数为此函数对象)

function observable() {

        if (arguments.length > 0) {

            // Write

 

            // Ignore writes if the value hasn't changed

            if (observable.isDifferent(observable[observableLatestValue], arguments[0])) {

                observable.valueWillMutate();

                observable[observableLatestValue] = arguments[0];

                observable.valueHasMutated();

            }

            return this; // Permits chained assignments        }

        else {

            debugger;

            // Read

            ko.dependencyDetection.registerDependency(observable); //执行依赖

            return observable[observableLatestValue];

        }

    }

8、在ko.dependencyDetection中的registerDependency方法内,首先会判断ko.observable是否为订阅对象,如果是则执行begin加入的callbak函数.

registerDependency: function (subscribable) { //注入到相关依赖属性

            if (currentFrame) {

                if (!ko.isSubscribable(subscribable))

                    throw new Error("Only subscribable things can act as dependencies");

                currentFrame.callback.call(currentFrame.callbackTarget, subscribable, subscribable._id || (subscribable._id = getId()));

            }

        }

9、执行evaluateImmediate方法后,然后注册Dom移除回调事件。

if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {

        ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {

            computedObservable.dispose();

        });

    }

10、返回computedObservable对象

四、补充说明

 

1ko.dependencyDetection中有ignore方法,他主要实现的是一个异步锁,让callbcak处于锁的状态执行

ignore: function (callback, callbackTarget, callbackArgs) { //按顺序s执行依赖,但不触发订阅。

            try {

                begin();

                return callback.apply(callbackTarget, callbackArgs || []);

            } finally {

                end();

            }

        }

2ko.computed 与 ko.dependentObservable是相同的。

 

 

 

 

原文来自:博客园/小龙女先生

您还未登录,请先登录

热门帖子

最新帖子