一、序列圖
二、主要程式碼檔案
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(); } }