回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针调用它所指向的函数时,我们就说这是回调函数。回调函数不是由该函数的实现方直接调用,而是在特定的事件或条件发生时由另外的一方调用的,用于对该事件或条件进行响应。

// 工具函数,将字符串格式的标记转换为对象格式,并把转换结果缓存起来
function createFlags( flags ) {//初始化返回值object和flagsCache[flags]为空对象,同时指向了同一个空对象,当变量object添加属性时也是在为flagsCache[flags]添加属性,不需要要再写一行代码把变量object放入缓存对象flagsCache中了var object = flagsCache[ flags ] = {},i, length;flags = flags.split( /\s+/ ); //用空白符把标记字符串分割为数组//遍历数组,为返回值object添加单个标记,属性值为true,最后返回对象for ( i = 0, length = flags.length; i < length; i++ ) {object[ flags[i] ] = true;}return object;
}jQuery.Callbacks = function( flags ) {// 解析字符串标记为flags为对象,先从缓存对象flagsCache中获取标记字符串flags对应的标记对象,如果没有找到,在调用工具函数createFlags(flags)将标记字符串flags解析为标记对象,并放入寒碜对象flagsCache中flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {};var // 声明局部变量,通过闭包机制引用list = [],//存放回调函数的数组//在可重复触发、正在执行的列表上,重复触发时,将上下文和参数放入数组stack中stack = [],memory,// fired,// 回调函数列表是否正在执行中firing,// 待执行的第一个回调函数的下标firingStart,// End of the loop when firingfiringLength,// Index of currently firing callback (modified by remove if needed)firingIndex,// 添加回调函数的工具函数add = function( args ) {var i,length,elem,type,actual;//遍历参数args,把回调函数逐个添加到数组list中,for ( i = 0, length = args.length; i < length; i++ ) {elem = args[ i ];type = jQuery.type( elem );//判断args[i]类型,如果是数组,则迭代调用规矩函数add(args)把数组中的回调函数添加到数组list中,if ( type === "array" ) {add( elem );} else if ( type === "function" ) {// 如果是函数且不是unique模式,或者是unique模式但未添加过,才会添加args[i]到数组中list中if ( !flags.unique || !self.has( elem ) ) {list.push( elem );}}}},// 触发回调函数的工具函数,使用上下文context和参数args调用数组list中的回调函数,该回调函数通过闭包机制引用数组list//参数context用于指定回调函数执行时的上下文,即关键字this所引用的对象,参数args用于指定调用回调函数时传入的参数fire = function( context, args ) {args = args || [];//若当前回调函数列表不是memory模式,则变量memory则被赋值为true,间接地表示当前回调函数列表已经被触发过memory = !flags.memory || [ context, args ];fired = true;firing = true;firingIndex = firingStart || 0;firingStart = 0;firingLength = list.length;for ( ; list && firingIndex < firingLength; firingIndex++ ) {//执行回调函数list[ firingIndex ],如果返回值是false,且当前回调函数列表是stopOnFalse模式,则变量memory被赋值为true,并停止执行后续的其他回调函数,if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {memory = true; // Mark as haltedbreak;}}firing = false;if ( list ) {//如果不是once模式,即可以多次触发回调函数列表,则从变量stack中弹出存放的下文和参数,再次执行整个回调函数列表,直到stack为空if ( !flags.once ) {if ( stack && stack.length ) {memory = stack.shift();self.fireWith( memory[ 0 ], memory[ 1 ] );}} else if ( memory === true ) {self.disable();} else {list = [];}}},// 回调函数列表,方法jQuery.Callbacks(flags)的返回值self = {// 添加回调函数add: function() {if ( list ) {//先备份数组list长度var length = list.length;add( arguments );// 如果回调函数正在执行,修正结束下标firingLength,使得新添加的回调函数也得以执行if ( firing ) {firingLength = list.length;// } else if ( memory && memory !== true ) {firingStart = length;fire( memory[ 0 ], memory[ 1 ] );}}return this;},// 移除回调函数,从回调函数列表中移除一个或一组回调函数,移除前修正结束下标firingLength和当前下班firingIndexremove: function() {if ( list ) {var args = arguments,argIndex = 0,argLength = args.length;//遍历待移除的回调函数数组,在循环体内嵌套遍历已有的回调函数数组,for ( ; argIndex < argLength ; argIndex++ ) {for ( var i = 0; i < list.length; i++ ) {//如果检查到某个待移除回调函数与某个已有的回调函数完全相等,则从已有的回调函数数组中移除它if ( args[ argIndex ] === list[ i ] ) {// 回调函数是否在列表中if ( firing ) {//如果回调函数列表正在执行                          if ( i <= firingLength ) {//在移除前使用结束下标firingLength减1                          firingLength--;//如果待移除函数的下标小于正在执行回调函数的下标firingIndex,即待移除的回调函数已经执行,则修正firingIndex减1,以确保不会漏执行回调函数                            if ( i <= firingIndex ) {firingIndex--;}}}// 调用数组原型方法splice(),从匹配下标处开始移除1个元素,循环变量i自减一,修正为下一个回调函数的下标list.splice( i--, 1 );/// 在unique模式下,数组list中不会有重复的回调函数,可以直接退出内层遍历,针对unique模式做的优化if ( flags.unique ) {break;}}}}}return this;},// 回调函数是都在列表中has: function( fn ) {if ( list ) {var i = 0,length = list.length;for ( ; i < length; i++ ) {if ( fn === list[ i ] ) {return true;}}}return false;},// 清空列表empty: function() {list = [];return this;},// 禁用列表disable: function() {list = stack = memory = undefined;return this;},// 是否已禁用列表disabled: function() {return !list;},// 锁定列表lock: function() {stack = undefined;if ( !memory || memory === true ) {self.disable();}return this;},// 是否已错定列表locked: function() {return !stack;},// 使用指定的上下文和参数调用回调函数fireWith: function( context, args ) {if ( stack ) {if ( firing ) {if ( !flags.once ) {stack.push( [ context, args ] );}} else if ( !( flags.once && memory ) ) {fire( context, args );}}return this;},// 使用指定的参数调用回调函数,上下文为self fire: function() {self.fireWith( this, arguments );return this;},// 回调函数列表是否至少执行过一次fired: function() {return !!fired;}};return self;
};

jQuery源码研究分析学习笔记-回调函数(11)相关推荐

  1. jQuery源码研究分析学习笔记-静态方法和属性(10)

    jQuery源码中定义了一些重要的静态属性和方法,它们是其他模块实现的基础,整体的源码结构如下 //把window.jQuery和winow.$备份到局部变量_jQuery和_$_jQuery = w ...

  2. jQuery源码研究分析学习笔记-jQuery.deferred()(12)

    JS是单线程语言,把每一件事情(包括GUI事件和渲染)都放在一个线程里来处理是一个很好的程序模型,因为这样就无需再考虑线程同步这些复杂问题. 但js暴露了应用开发中的一个严重问题,单线程环境看起来对用 ...

  3. jQuery源码研究分析学习笔记-jQuery.extend()、jQuery.fn.extend()(八)

    jQuery.extend().jQuery.fn.extend()主要用于编写插件和处理函数参数. jQuery.extend(deep,target,objdect1 [,objectN]) jQ ...

  4. jQuery源码研究分析学习笔记-jQuery.fn.init()(五)

    $()=jQuery(),二者即是返回的构造函数jQuery.fn.init()实例对象 jQuery = function( selector, context ) {return new jQue ...

  5. jQuery源码研究分析学习笔记-jQuery.buildFragment()(六)

    DocumentFragment是一种特殊的Node,它作为其他节点的一个临时容器,像document节点咿呀,DocumentFragment是独立的,而不是任何其他文档的一部分,它的parentN ...

  6. jQuery源码研究学习笔记(二)

    jQuery总体架构: jQuery模块可以大致分为三部分:入口模块.底层支持模块.功能模块. 参考jQuery技术内幕解析 jquery源码总体架构: (function(window,undefi ...

  7. jquery源码之低调的回调函数队列--Callbacks

    jQuery中有一个很实用的函数队列,可能我们很少用到,但他在jQuery内部却有着举足轻重的地位. 他就是Callbacks. jQuery作者用它构建了很多非常重要的模块.比如说$.Deferre ...

  8. jQuery源码逐行分析学习01(jQuery的框架结构简化)

    最近在学习jQuery源码,在此,特别做一个分享,把所涉及的内容都记录下来,其中有不妥之处还望大家指出,我会及时改正.望各位大神不吝赐教!同时,这也是我的第一篇前端技术博客,对博客编写还不是很熟悉,美 ...

  9. javascript arguments对象研究--针对jquery源码研究再研究

    外部插件: $.fn.tinytip = function(text, customOptions) {     debugger;         if (text && typeo ...

最新文章

  1. 程序员崩溃的10个瞬间
  2. oracle imp 工具可能出现的问题
  3. js学习笔记9----时间操作
  4. sql 自动递增 在java_java基础 之 操作符
  5. Starting MySQL.. ERROR! The server quit without updating PID file (/usr/local/mysql/data/vm10-0-0-19
  6. keepalived 服务器内存持续升高问题
  7. Quartz.net 开源job调度框架(二)----定点执行
  8. 微信小程序点击button按钮后重置输入框等表单内容
  9. C语言打印输出红色字体
  10. Java集合(1)--集合概述
  11. pandas 根据单号分类_由 “猫捉老鼠”游戏联想的用户分类问题
  12. mybatis 执行插入操作,insert 返回1,数据库中无数据。数据库中数据的创建时间和插入执行时间不一致。
  13. Qt工作笔记-把QTableWidget数据存为XML,启动时加载XML
  14. Memory Management Concepts overview(内存管理基本概念)
  15. Q142:PBRT-V3,交点处各种微分的求解(三角形,3.6章节)
  16. 我以为内卷是外包的反义词!
  17. 设置Kafka集群的方法
  18. java程序设计精编教程第3版电子版课后答案_Java程序设计精编教程(第3版)-微课版...
  19. 低代码真的是“行业毒瘤”?
  20. 用辅助功能实现自动点击

热门文章

  1. 分布式系统 c语言,C语言分布式系统中的进程标识!
  2. windows下apache并发php,windows环境下apache死机问题的解决一例
  3. JVM内存模型与GC回收器
  4. Python学习入门9:如何高效学Python?
  5. 基于人人网的Android开发流程介绍
  6. Ubuntu12.04 下配置tomcat
  7. 教你50招提升ASP.NET性能(二十六):对于开发人员的数据库性能技巧
  8. [AWDwR4] No JQuery call matches [:html, #cart]
  9. DataGrid中加入CheckBox,并实现单选
  10. Kubernetes理论02