knockout依賴屬性是什么?也許看了教程還是迷迷糊糊,這里就給大家用源碼來一個(gè)knockout學(xué)習(xí)教程吧,希望大家能夠弄懂knockout的依賴屬性。
一、序列圖
一、主要代碼文件
1、dependentObservable.js:主要包含ko.computed相關(guān)方法的處理
2、dependencyDetection.js:主要包含依賴的監(jiān)控上下文對(duì)象。
三、主要邏輯
1、首先為某個(gè)屬性定義 一個(gè)computed對(duì)象,如下源碼:
var vModel = function(){
this.fName = ko.observable('fName'),
this.lName= ko.observable('lName'),
this.name= ko.computed(function () { //監(jiān)控依賴對(duì)象
return this.fName() + '-' + this.lName();
},this);
};
2、當(dāng)代碼在執(zhí)行ko.computed方法,求值方法被作為參數(shù)傳入,并賦值給options的read屬性
3、創(chuàng)建一個(gè)state字面量對(duì)象,其中包含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
};
4、生成computedObservable對(duì)象(function),然后將state附加到_state屬性上,則擴(kuò)展為發(fā)布/訂閱對(duì)象。
5、擴(kuò)展computedFn所有方法和屬性到computedObservable對(duì)象上
// 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); //執(zhí)行發(fā)布/訂閱對(duì)象的init方法,用于初始化發(fā)布/訂閱對(duì)象。
// Inherit from 'computed'
ko.utils.setPrototypeOfOrExtend(computedObservable, computedFn);
6、然后執(zhí)行computedObservable的evaluateImmediate方法,此方法中最重的三點(diǎn):
6.1、在evaluateImmediate_CallReadWithDependencyDetection方法中,創(chuàng)建了依賴監(jiān)控對(duì)象,并添加到依賴監(jiān)控上下文中
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、然后調(diào)用evaluateImmediate_CallReadThenEndDependencyDetection方法,參數(shù)傳遞的state(在ko.computed方法中定義的)、dependencyDetectionContext(依賴監(jiān)控對(duì)象)
6.3、其中用到了try catch finall方式,確保ko.dependencyDetection.end方法的執(zhí)行
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、在執(zhí)行ko.computed的readFunction方法時(shí),其中就執(zhí)行了ko.observable方法(執(zhí)行的是read),這時(shí)就會(huì)去調(diào)用ko.dependencyDetection.registerDependency方法(參數(shù)為此函數(shù)對(duì)象)
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); //執(zhí)行依賴
return observable[observableLatestValue];
}
}
8、在ko.dependencyDetection中的registerDependency方法內(nèi),首先會(huì)判斷ko.observable是否為訂閱對(duì)象,如果是則執(zhí)行begin加入的callbak函數(shù).
registerDependency: function (subscribable) { //注入到相關(guān)依賴屬性
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、執(zhí)行evaluateImmediate方法后,然后注冊(cè)Dom移除回調(diào)事件。
if (state.disposeWhenNodeIsRemoved && computedObservable.isActive()) {
ko.utils.domNodeDisposal.addDisposeCallback(state.disposeWhenNodeIsRemoved, state.domNodeDisposalCallback = function () {
computedObservable.dispose();
});
}
10、返回computedObservable對(duì)象
四、補(bǔ)充說明
1、ko.dependencyDetection中有ignore方法,他主要實(shí)現(xiàn)的是一個(gè)異步鎖,讓callbcak處于鎖的狀態(tài)執(zhí)行
ignore: function (callback, callbackTarget, callbackArgs) { //按順序s執(zhí)行依賴,但不觸發(fā)訂閱。
try {
begin();
return callback.apply(callbackTarget, callbackArgs || []);
} finally {
end();
}
}
2、ko.computed 與 ko.dependentObservable是相同的。
原文來自:博客園/小龍女先生