knockout源码分析之执行过程
一、执行流程

二、主要类分析
2.1. 在applyBindings中,创建bindingContext,然后执行applyBindingsToNodeAndDescendantsInternal方法
2.2. 在applyBindinsToNodeAndDescendantsInteranl方法,主要完成当前Node的绑定,以及子Node的绑定
function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {
var shouldBindDescendants = true;
// Perf optimisation: Apply bindings only if...
// (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
// Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
// (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
var isElement = (nodeVerified.nodeType === 1);
if (isElement) // Workaround IE <= 8 HTML parsing weirdness
ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement) // Case (1)
|| ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified); // Case (2)
if (shouldApplyBindings)
shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];
if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {
// We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
// * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
// hence bindingContextsMayDifferFromDomParentElement is false
// * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
// skip over any number of intermediate virtual elements, any of which might define a custom binding context,
// hence bindingContextsMayDifferFromDomParentElement is true
applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
}
}
2.3. 进入applyBindingsToNodeInternal方法,其中会调用bindingProvider的getBindingsAccessors方法(用于分析和获取bindings数据,主要分析data-bind属性)
2.4. 创建dependentObservable对象(依赖监控对象)
var bindings;
if (sourceBindings && typeof sourceBindings !== 'function') {
bindings = sourceBindings;
} else {
var provider = ko.bindingProvider['instance'],
getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors; //自定义BingindHandler // Get the binding from the provider within a computed observable so that we can update the bindings whenever
// the binding context is updated or if the binding provider accesses observables.
var bindingsUpdater = ko.dependentObservable( //依赖监控对象
function() { //做了read、write处理,实现双向关联(只做了read),默认会执行一次read的。
bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);
// Register a dependency on the binding context to support observable view models.
if (bindings && bindingContext._subscribable)
bindingContext._subscribable();
return bindings;
},
null, { disposeWhenNodeIsRemoved: node }
); if (!bindings || !bindingsUpdater.isActive())
bindingsUpdater = null;
}
2.5. 然后分析bindings中每个binding,并将init、update方法创建为一个dependentObservable对象(其中bindings的执行是有顺序的)。
三、BindingProvider分析
此类主要提供关于data-bind属性的解析,主要提供getBindings、getBindingsAccessors、parseBindingsString(内容使用)方法辅助binding过程。创建function对象:
function createBindingsStringEvaluator(bindingsString, options) {
// Build the source for a function that evaluates "expression"
// For each scope variable, add an extra level of "with" nesting
// Example result: with(sc1) { with(sc0) { return (expression) } }
var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),
functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}"; //执行with表达式
return new Function("$context", "$element", functionBody);
}
1、在分析bindings时,会区分NodeType为1、8的类型。如果是8(注释)就会调用virtualElements类的virtualNodeBindingValue方法来分析binding结果。
四、bindings的排序技巧
查看自定义binding是否有after属性,如果存在则进行递归操作:
function topologicalSortBindings(bindings) {
// Depth-first sort
var result = [], // The list of key/handler pairs that we will return
bindingsConsidered = {}, // A temporary record of which bindings are already in 'result'
cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
if (!bindingsConsidered[bindingKey]) {
var binding = ko['getBindingHandler'](bindingKey);
if (binding) {
// First add dependencies (if any) of the current binding
if (binding['after']) { //依赖检测,将after的引用先添加到数组中,然后再添加当前项
cyclicDependencyStack.push(bindingKey);
ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {
if (bindings[bindingDependencyKey]) {
if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {
throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
} else {
pushBinding(bindingDependencyKey);
}
}
});
cyclicDependencyStack.length--;
}
// Next add the current binding
result.push({ key: bindingKey, handler: binding });
}
bindingsConsidered[bindingKey] = true;
}
});
五、注意
1.所有的dependentObservable对象,在创建的过程中都会默认执行一次readFunction方法。
knockout源码分析之执行过程的更多相关文章
- 深入源码分析SpringMVC执行过程
本文主要讲解 SpringMVC 执行过程,并针对相关源码进行解析. 首先,让我们从 Spring MVC 的四大组件:前端控制器(DispatcherServlet).处理器映射器(HandlerM ...
- 精尽MyBatis源码分析 - SQL执行过程(二)之 StatementHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - SQL执行过程(三)之 ResultSetHandler
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- 精尽MyBatis源码分析 - SQL执行过程(四)之延迟加载
该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...
- SOFA 源码分析 —— 服务引用过程
前言 在前面的 SOFA 源码分析 -- 服务发布过程 文章中,我们分析了 SOFA 的服务发布过程,一个完整的 RPC 除了发布服务,当然还需要引用服务. So,今天就一起来看看 SOFA 是如何引 ...
- Dubbo 源码分析 - 服务调用过程
注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...
- MyBatis 源码分析 - 配置文件解析过程
* 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...
- 源码分析HotSpot GC过程(一)
«上一篇:源码分析HotSpot GC过程(一)»下一篇:源码分析HotSpot GC过程(三):TenuredGeneration的GC过程 https://blogs.msdn.microsoft ...
- 源码分析HotSpot GC过程(三):TenuredGeneration的GC过程
老年代TenuredGeneration所使用的垃圾回收算法是标记-压缩-清理算法.在回收阶段,将标记对象越过堆的空闲区移动到堆的另一端,所有被移动的对象的引用也会被更新指向新的位置.看起来像是把杂陈 ...
随机推荐
- ASP.NET MVC图片管理(上传,预览与显示)
先看看效果(下面gif动画制作有点大,5.71MB): 题外话:上面选择图片来源于Insus.NET的新浪微博:http://weibo.com/104325017 也是昨晚(2015-07-03)I ...
- ECshop 快捷登录插件 支持QQ 支付宝 微博
亲自测试可以使用,分享给大家.(承接各种EcShop改版,二次开发等相关项目 QQ:377898650) 安装的时候按照里面说明.安装即可. 代码下载:http://pan.baidu.com/s/1 ...
- Yii2的深入学习--入口文件
前一段时间,尝试去写一个 php 的简单框架,发现自己还欠缺很多,就暂时停掉了.准备先读完 Yii2 的源码,然后再去看完 laravel 的源码,最后再继续去写这个简单的 php 框架. 之后关于 ...
- 算法与数据结构(2)--英雄会第三届在线编程大赛:几个bing
基础知识的回顾不再写到这里面了,会写一些算法算法的解答或者读一些相关书籍的笔记. 今天做了一道算法题,来自微软必应·英雄会第三届在线编程大赛:几个bing? 做出来了...但不知道为啥执行测试用例失败 ...
- [译]学习IPython进行交互式计算和数据可视化(六)
第五章:高性能并行计算 一个反复被提及的反对使用Python进行高性能数值计算的言论是这种语言是动态解释型的,速度太慢.一种编译型低级语言,如C,能提供比它快几个数量级的运算速度.我们在第三章--使用 ...
- 用Visual Studio Code 开发应用之 安装 Visual Studio Code
最近研究微软的ASP.NET 新一代产品 ASP.NET Core1.0. 发先Visual Studio Code是一个很好的很强大的开源编辑器.是编辑器而不是IDE.之所以强大是因为他可以说是一个 ...
- Asp.net(C#) windows 服务{用于实现计划任务,事件监控等}
什么是windows服务? 一个Windows服务程序是在Windows操作系统下能完成特定功能的可执行的应用程序.Windows服务程序虽然是可执行的,但是它不像一般的可执行文件通过双击就 ...
- 图的存储及遍历 深度遍历和广度遍历 C++代码实现
/*图的存储及遍历*/ #include<iostream> using namespace std; //----------------------------------- //邻接 ...
- Nancy FormsAuthentication使用
1.新建UserDatabase类,实现IUserMapper接口 using System; using System.Collections.Generic; using System.Linq; ...
- 孙鑫MFC学习笔记13:文档
1.CArchive类保存内存数据 2.CAchive类重载了>>与<<操作符,类似C++文件流 3.在OnNewDocument中通过SetTitle设置标题 4.字符串资源 ...