一、序列图
二、主要代码文件
1、dependentObservable.js:主要包含ko.computed相关方法的处理
2、dependencyDetection.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); };
3、创建一个state字面量对象,其中包含read、write属性,如下代码:
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 };
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.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.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; }
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]; } }
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())); } }
if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) { ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () { computedObservable.dispose(); }); }
四、补充说明
1、ko.dependencyDetection中有ignore方法,他主要实现的是一个异步锁,让callbcak处于锁的状态执行
ignore: function (callback, callbackTarget, callbackArgs) { //按顺序s执行依赖,但不触发订阅。 try { begin(); return callback.apply(callbackTarget, callbackArgs || []); } finally { end(); } }