一、执行流程

二、主要类分析

2.1. 在applyBindings中,创建bindingContext,然后执行applyBindingsToNodeAndDescendantsInternal方法
2.2. 在applyBindinsToNodeAndDescendantsInteranl方法,主要完成当前Node的绑定,以及子Node的绑定

  1. function applyBindingsToNodeAndDescendantsInternal (bindingContext, nodeVerified, bindingContextMayDifferFromDomParentElement) {
  2. var shouldBindDescendants = true;
  3.  
  4. // Perf optimisation: Apply bindings only if...
  5. // (1) We need to store the binding context on this node (because it may differ from the DOM parent node's binding context)
  6. // Note that we can't store binding contexts on non-elements (e.g., text nodes), as IE doesn't allow expando properties for those
  7. // (2) It might have bindings (e.g., it has a data-bind attribute, or it's a marker for a containerless template)
  8. var isElement = (nodeVerified.nodeType === 1);
  9. if (isElement) // Workaround IE <= 8 HTML parsing weirdness
  10. ko.virtualElements.normaliseVirtualElementDomStructure(nodeVerified);
  11.  
  12. var shouldApplyBindings = (isElement && bindingContextMayDifferFromDomParentElement) // Case (1)
  13. || ko.bindingProvider['instance']['nodeHasBindings'](nodeVerified); // Case (2)
  14. if (shouldApplyBindings)
  15. shouldBindDescendants = applyBindingsToNodeInternal(nodeVerified, null, bindingContext, bindingContextMayDifferFromDomParentElement)['shouldBindDescendants'];
  16.  
  17. if (shouldBindDescendants && !bindingDoesNotRecurseIntoElementTypes[ko.utils.tagNameLower(nodeVerified)]) {
  18. // We're recursing automatically into (real or virtual) child nodes without changing binding contexts. So,
  19. // * For children of a *real* element, the binding context is certainly the same as on their DOM .parentNode,
  20. // hence bindingContextsMayDifferFromDomParentElement is false
  21. // * For children of a *virtual* element, we can't be sure. Evaluating .parentNode on those children may
  22. // skip over any number of intermediate virtual elements, any of which might define a custom binding context,
  23. // hence bindingContextsMayDifferFromDomParentElement is true
  24. applyBindingsToDescendantsInternal(bindingContext, nodeVerified, /* bindingContextsMayDifferFromDomParentElement: */ !isElement);
  25. }
  26. }

2.3. 进入applyBindingsToNodeInternal方法,其中会调用bindingProvider的getBindingsAccessors方法(用于分析和获取bindings数据,主要分析data-bind属性)
2.4. 创建dependentObservable对象(依赖监控对象)

  1. var bindings;
  2. if (sourceBindings && typeof sourceBindings !== 'function') {
  3. bindings = sourceBindings;
  4. } else {
  5. var provider = ko.bindingProvider['instance'],
  6. getBindings = provider['getBindingAccessors'] || getBindingsAndMakeAccessors; //自定义BingindHandler
  7.  
  8. // Get the binding from the provider within a computed observable so that we can update the bindings whenever
  9. // the binding context is updated or if the binding provider accesses observables.
  10. var bindingsUpdater = ko.dependentObservable( //依赖监控对象
  11. function() { //做了read、write处理,实现双向关联(只做了read),默认会执行一次read的。
  12. bindings = sourceBindings ? sourceBindings(bindingContext, node) : getBindings.call(provider, node, bindingContext);
  13. // Register a dependency on the binding context to support observable view models.
  14. if (bindings && bindingContext._subscribable)
  15. bindingContext._subscribable();
  16. return bindings;
  17. },
  18. null, { disposeWhenNodeIsRemoved: node }
  19. );
  20.  
  21. if (!bindings || !bindingsUpdater.isActive())
  22. bindingsUpdater = null;
  23. }

2.5. 然后分析bindings中每个binding,并将init、update方法创建为一个dependentObservable对象(其中bindings的执行是有顺序的)。

三、BindingProvider分析

此类主要提供关于data-bind属性的解析,主要提供getBindings、getBindingsAccessors、parseBindingsString(内容使用)方法辅助binding过程。创建function对象:

  1. function createBindingsStringEvaluator(bindingsString, options) {
  2. // Build the source for a function that evaluates "expression"
  3. // For each scope variable, add an extra level of "with" nesting
  4. // Example result: with(sc1) { with(sc0) { return (expression) } }
  5. var rewrittenBindings = ko.expressionRewriting.preProcessBindings(bindingsString, options),
  6. functionBody = "with($context){with($data||{}){return{" + rewrittenBindings + "}}}"; //执行with表达式
  7. return new Function("$context", "$element", functionBody);
  8. }

1、在分析bindings时,会区分NodeType为1、8的类型。如果是8(注释)就会调用virtualElements类的virtualNodeBindingValue方法来分析binding结果。

四、bindings的排序技巧

查看自定义binding是否有after属性,如果存在则进行递归操作:

  1. function topologicalSortBindings(bindings) {
  2. // Depth-first sort
  3. var result = [], // The list of key/handler pairs that we will return
  4. bindingsConsidered = {}, // A temporary record of which bindings are already in 'result'
  5. cyclicDependencyStack = []; // Keeps track of a depth-search so that, if there's a cycle, we know which bindings caused it
  6. ko.utils.objectForEach(bindings, function pushBinding(bindingKey) {
  7. if (!bindingsConsidered[bindingKey]) {
  8. var binding = ko['getBindingHandler'](bindingKey);
  9. if (binding) {
  10. // First add dependencies (if any) of the current binding
  11. if (binding['after']) { //依赖检测,将after的引用先添加到数组中,然后再添加当前项
  12. cyclicDependencyStack.push(bindingKey);
  13. ko.utils.arrayForEach(binding['after'], function(bindingDependencyKey) {
  14. if (bindings[bindingDependencyKey]) {
  15. if (ko.utils.arrayIndexOf(cyclicDependencyStack, bindingDependencyKey) !== -1) {
  16. throw Error("Cannot combine the following bindings, because they have a cyclic dependency: " + cyclicDependencyStack.join(", "));
  17. } else {
  18. pushBinding(bindingDependencyKey);
  19. }
  20. }
  21. });
  22. cyclicDependencyStack.length--;
  23. }
  24. // Next add the current binding
  25. result.push({ key: bindingKey, handler: binding });
  26. }
  27. bindingsConsidered[bindingKey] = true;
  28. }
  29. });

五、注意

1.所有的dependentObservable对象,在创建的过程中都会默认执行一次readFunction方法。

knockout源码分析之执行过程的更多相关文章

  1. 深入源码分析SpringMVC执行过程

    本文主要讲解 SpringMVC 执行过程,并针对相关源码进行解析. 首先,让我们从 Spring MVC 的四大组件:前端控制器(DispatcherServlet).处理器映射器(HandlerM ...

  2. 精尽MyBatis源码分析 - SQL执行过程(二)之 StatementHandler

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  3. 精尽MyBatis源码分析 - SQL执行过程(三)之 ResultSetHandler

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  4. 精尽MyBatis源码分析 - SQL执行过程(四)之延迟加载

    该系列文档是本人在学习 Mybatis 的源码过程中总结下来的,可能对读者不太友好,请结合我的源码注释(Mybatis源码分析 GitHub 地址.Mybatis-Spring 源码分析 GitHub ...

  5. SOFA 源码分析 —— 服务引用过程

    前言 在前面的 SOFA 源码分析 -- 服务发布过程 文章中,我们分析了 SOFA 的服务发布过程,一个完整的 RPC 除了发布服务,当然还需要引用服务. So,今天就一起来看看 SOFA 是如何引 ...

  6. Dubbo 源码分析 - 服务调用过程

    注: 本系列文章已捐赠给 Dubbo 社区,你也可以在 Dubbo 官方文档中阅读本系列文章. 1. 简介 在前面的文章中,我们分析了 Dubbo SPI.服务导出与引入.以及集群容错方面的代码.经过 ...

  7. MyBatis 源码分析 - 配置文件解析过程

    * 本文速览 由于本篇文章篇幅比较大,所以这里拿出一节对本文进行快速概括.本篇文章对 MyBatis 配置文件中常用配置的解析过程进行了较为详细的介绍和分析,包括但不限于settings,typeAl ...

  8. 源码分析HotSpot GC过程(一)

    «上一篇:源码分析HotSpot GC过程(一)»下一篇:源码分析HotSpot GC过程(三):TenuredGeneration的GC过程 https://blogs.msdn.microsoft ...

  9. 源码分析HotSpot GC过程(三):TenuredGeneration的GC过程

    老年代TenuredGeneration所使用的垃圾回收算法是标记-压缩-清理算法.在回收阶段,将标记对象越过堆的空闲区移动到堆的另一端,所有被移动的对象的引用也会被更新指向新的位置.看起来像是把杂陈 ...

随机推荐

  1. Android线程处理之Handler

    上一篇已经简单为大家介绍了一下关于Handler的使用,本篇我们就一起再来探讨一下Handler的高级使用,上一篇我们仅仅是简单的进行UI界面的更新,本篇我们来一起探讨一下如何把子线程的数据发送到主线 ...

  2. Zookeeper-Zookeeper的配置

    前面两篇文章介绍了Zookeeper是什么和可以干什么,那么接下来我们就实际的接触一下Zookeeper这个东西,看看具体如何使用,有个大体的感受,后面再描述某些地方的时候也能在大脑中有具体的印象.本 ...

  3. 记一次上传文件到七牛云存储的经历(Plupload & UEditor)(.net)

    七牛 配置ACCESS_KEY和SECRET_KEY Qiniu.Conf.Config.ACCESS_KEY = "ACCESS_KEY"; Qiniu.Conf.Config. ...

  4. IP,路由,交换基础培训记录

    IP 掩码  子网划分 vlan划分(有助于减少广播压力) vlan之间互通通过交换机打通. 路由,静态路由,动态路由(学习到的),路由表,下一跳,网络位长的优先级高. 交换机,hub集线器. hub ...

  5. selenium-webdriver(python) (十三) -- cookie处理

    本节重点: driver.get_cookies() 获得cookie信息 add_cookie(cookie_dict)  向cookie添加会话信息 delete_cookie(name)   删 ...

  6. Hadoop阅读笔记(六)——洞悉Hadoop序列化机制Writable

    酒,是个好东西,前提要适量.今天参加了公司的年会,主题就是吃.喝.吹,除了那些天生话唠外,大部分人需要加点酒来作催化剂,让一个平时沉默寡言的码农也能成为一个喷子!在大家推杯换盏之际,难免一些画面浮现脑 ...

  7. WEB编程中获取src目录下的文件(没有src目录)

    这种情况遇见的会比较多,像一个WEB工程,如果在src下面写了一个xml或者一些其它的文件,当工程发布到服务器时,web程序是在tomcat等服务器下运行这个程序的,这个时候,程序目录里面并没有src ...

  8. 【模式匹配】Aho-Corasick自动机

    1. 多模匹配 AC自动机(Aho-Corasick Automaton)是多模匹配算法的一种.所谓多模匹配,是指在字符串匹配中,模式串有多个.前面所介绍的KMP.BM为单模匹配,即模式串只有一个.假 ...

  9. Elasticsearch——集群相关的配置

    cluster模块主要用于控制分片在节点上如何进行分配,以及何时进行重新分配 概览 下面的一些资料可以进行相关的配置: Cluster Level Shard Allocation用于配置集群中节点如 ...

  10. MVC导出数据到EXCEL新方法:将视图或分部视图转换为HTML后再直接返回FileResult

    导出EXCEL方法总结 MVC导出数据到EXCEL的方法有很多种,常见的是: 1.采用EXCEL COM组件来动态生成XLS文件并保存到服务器上,然后转到该文件存放路径即可: 优点:可设置丰富的EXC ...