一、序列图

二、主要代码文件

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);
};

2、当代码在执行ko.computed方法,求值方法被作为参数传入,并赋值给options的read属性
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
};

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、然后执行computedObservable的evaluateImmediate方法,此方法中最重的三点:
   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.computed的readFunction方法时,其中就执行了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对象

四、补充说明

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

ignore: function (callback, callbackTarget, callbackArgs) { //按顺序s执行依赖,但不触发订阅。
try {
begin();
return callback.apply(callbackTarget, callbackArgs || []);
} finally {
end();
}
}

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

knockout源码分析之computed(依赖属性)的更多相关文章

  1. 使用react全家桶制作博客后台管理系统 网站PWA升级 移动端常见问题处理 循序渐进学.Net Core Web Api开发系列【4】:前端访问WebApi [Abp 源码分析]四、模块配置 [Abp 源码分析]三、依赖注入

    使用react全家桶制作博客后台管理系统   前面的话 笔者在做一个完整的博客上线项目,包括前台.后台.后端接口和服务器配置.本文将详细介绍使用react全家桶制作的博客后台管理系统 概述 该项目是基 ...

  2. Spring源码分析之循环依赖及解决方案

    Spring源码分析之循环依赖及解决方案 往期文章: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostPro ...

  3. Spring 源码分析之 bean 依赖注入原理(注入属性)

         最近在研究Spring bean 生命周期相关知识点以及源码,所以打算写一篇 Spring bean生命周期相关的文章,但是整理过程中发现涉及的点太多而且又很复杂,很难在一篇文章中把Spri ...

  4. ABP源码分析六:依赖注入的实现

    ABP的依赖注入的实现有一个本质两个途径:1.本质上是依赖于Castle这个老牌依赖注入的框架.2.一种实现途径是通过实现IConventionalDependencyRegistrar的实例定义注入 ...

  5. [Abp 源码分析]三、依赖注入

    0.简要介绍 在 Abp 框架里面,无时无刻不存在依赖注入,关于依赖注入的作用与好处我就不在这里多加赘述了,网上有很多解释的教程.在 [Abp 源码分析]一.Abp 框架启动流程分析 里面已经说过,A ...

  6. knockout源码分析之执行过程

    一.执行流程 二.主要类分析 2.1. 在applyBindings中,创建bindingContext,然后执行applyBindingsToNodeAndDescendantsInternal方法 ...

  7. knockout源码分析之订阅

    一.主类关系图 二.类职责 2.1.observable(普通监控对象类) observable(他其是一个function)的内部实现:1.首先声明一个名为observable的fn(这个可以说是一 ...

  8. 六.jQuery源码分析之jQuery原型属性和方法

    97 jQuery.fn = jQuery.prototype = { 98 constructor: jQuery, 99 init: function( selector, context, ro ...

  9. Spring源码分析之Bean的创建过程详解

    前文传送门: Spring源码分析之预启动流程 Spring源码分析之BeanFactory体系结构 Spring源码分析之BeanFactoryPostProcessor调用过程详解 本文内容: 在 ...

随机推荐

  1. android 手机开启debug日志

    来自 http://blog.csdn.net/aikongmeng/article/details/9764297 真机默认是不开启Log 开关的,这么来说我们如果使用真机来搞程序测试的话,需要做以 ...

  2. Cwinux源码解析(三)

    我在我的 薛途的博客 上发表了新的文章,欢迎各位批评指正. Cwinux源码解析(三)

  3. Android基于mAppWidget实现手绘地图(十五)–如何控制放大缩小

    一般来说,可以使用以下几种方式来控制地图的放大/缩小 : 1. 使用控件底部的缩放按钮 2.双击控件 3.pinch手势 4.物理按键 :I键标识缩小  :O键表示放大.(只有设备具有物理按键才行) ...

  4. [C] C++对C的部分扩充

    C语言只允许变量在程序(或函数)开始处定义,而C++允许变量在程序的任何位置定义. C语言中没有定义作用域限定运算符. C语言中没有布尔类型. C++中关于枚举类型和结构类型的定义更加简洁. C++新 ...

  5. hadoop的概念

    hadoop的概念 网上会经常遇到各种hadoop的概念,Hive,HBase,Hdfs都各是什么呢? 首先从hdfs说起,hdfs是分布式文件系统,它把集群当作单机一样做文件操作,文件可能存在于多个 ...

  6. EF总结

    1.Entity Framework 查询历史最严重bug求解十万火急 2.http://www.cnblogs.com/badly1984/p/3203565.html 3.Entity Frame ...

  7. AndroidDevTools简介

    AndroidDevTools简介 Android Dev Tools官网地址:www.androiddevtools.cn 收集整理Android开发所需的Android SDK.开发中用到的工具. ...

  8. The conversion of a varchar data type to a datetime data type resulted in an out-of-range value

    刚刚有在程序中,传递一个空值至MS SQL Server数据库,这个值的数据类型为DATETIME执行时,它却发生了如标题提示的异常:The conversion of a varchar data ...

  9. SQL中 将同一个表中的A列更新到B列,B列更新到A列

    有网友在SKYPE问及,如标题,SQL中 将同一个表中的A列更新到B列,B列更新到A列. 其实这个不是问题,直接写更新语句即可,可以参考下面动画演示: SQL source code: CREATE ...

  10. MVC上传文件

    ASP.NET MVC上传文件是必段撑握的知识.加强训练才是.以前Insus.NET曾使用第三方MyAjaxForm.js :http://www.cnblogs.com/insus/p/378548 ...