(function( jQuery ) {

 // String to Object flags format cache
var flagsCache = {}; // Convert String-formatted flags into Object-formatted ones and store in cache
// 将字符串形式的flags转换成对象形式,并且存到cache中,例: "once memory" => {"once":true,"memory":true}
function createFlags( flags ) {
var object = flagsCache[ flags ] = {},
i, length;
flags = flags.split( /\s+/ );
for ( i = , length = flags.length; i < length; i++ ) {
object[ flags[i] ] = true;
}
return object;
} /*
* 用以下参数创建一个回调函数列表:
*
* flags: 可选的以空格分隔的flags,会影响回调函数列表的行为
*
*
* 默认情况下,回调函数列表的行为如同一个事件回调函数列表一样,并且可以触发多次。
*
* 可选的 flags:
*
* once: 会确保回调列表只被触发一次(像Deferred一样), 这个不会阻止memory模式,也就是说 "once memory"的参数下 虽然只能fire一次,但是fire后再add 还是有效果的
*
* memory: 会记录上一次fire的上下文(一般是$.callbacks自身)和参数,并且会立即以最近一次fire记录下的上下文和参数执行新添加进来回调函数 (像Deferred一样)
* 具体看 (1) 88行 memory = !flags.memory || [ context, args ]; 保存memory模式下的 函数上下文和参数
* (2) 127-130行 self.add添加回调函数时候的处理
*
* unique: 会确同一个回调函数只在列表中出现一次
*
* stopOnFalse: 其中一个回调函数返回false即停止调用其余函数
*
*/
jQuery.Callbacks = function( flags ) { // Convert flags from String-formatted to Object-formatted
// (we check in cache first)
flags = flags ? ( flagsCache[ flags ] || createFlags( flags ) ) : {}; var // 实际存放回调函数的容器
list = [], // 用以存放可重复fire(即非once模式),重复fire的回调函数 例: 在一个回调函数体里边也调用了fire的情景
// 另外这个stack 还用以标示整个回调列表是否处于锁定状态(仅仅判可不可触发fire, 还是可以add, remove的) 205行 + 192-202行
stack = [], // 上次fire的上下文和参数,
// 可能的值: (1) [context,args]
// (2) true , 非记忆执行上下文和参数 或者 stopOnFalse模式下有返回为false的回调函数
memory,
// 标识当前是否处于fire状态
firing,
// fire第一个执行的回调函数在list中的索引位置 (内部fireWith使用和add导致list个数变化时修正执行中的索引位置 128行)
firingStart,
// 循环的结尾位置 (如果在firing状态下self.add添加新函数和self.remove移除函数时候会调整 123行 146行 )
firingLength,
// 当前触发的函数索引 ,需要的时候会调整
firingIndex,
//工具方法: 添加一个或多个(args为数组时)函数到list
add = function( args ) {
var i,
length,
elem,
type,
actual;
for ( i = , length = args.length; i < length; i++ ) {
elem = args[ i ];
type = jQuery.type( elem );
if ( type === "array" ) {
// 递归检查
add( elem );
} else if ( type === "function" ) {
// 非unique模式且新回调函数不存在
if ( !flags.unique || !self.has( elem ) ) {
list.push( elem );
}
}
}
},
//工具方法: 触发回调函数
fire = function( context, args ) {
args = args || [];
memory = !flags.memory || [ context, args ];
firing = true;
firingIndex = firingStart || ;
firingStart = ;
firingLength = list.length;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
if ( list[ firingIndex ].apply( context, args ) === false && flags.stopOnFalse ) {
memory = true; // 标记为终止 注意看106行, 销毁$.callbacks
break;
}
}
firing = false; // 标记执行结束
if ( list ) {
if ( !flags.once ) { // fire完后检查是否有回调函数内部重复fire保留下来的执行上下文和参数
if ( stack && stack.length ) {
memory = stack.shift();
self.fireWith( memory[ ], memory[ ] );
}
} else if ( memory === true ) { // stopOnFalse
self.disable();
} else {
list = [];
}
}
},
// 实际的回调函数对象
self = {
//实例方法: 添加一个或多个(args为数组时)函数到list
add: function() {
if ( list ) {
var length = list.length;
add( arguments );
// Do we need to add the callbacks to the
// current firing batch?
if ( firing ) {
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away, unless previous
// firing was halted (stopOnFalse)
} else if ( memory && memory !== true ) {
firingStart = length;
fire( memory[ ], memory[ ] );
}
}
return this;
},
// 从列表中移除函数
remove: function() {
if ( list ) {
var args = arguments,
argIndex = ,
argLength = args.length;
for ( ; argIndex < argLength ; argIndex++ ) {
for ( var i = ; i < list.length; i++ ) {
if ( args[ argIndex ] === list[ i ] ) {
// 在firing时移除函数,需要修正当前索引firingIndex和长度firingLength
if ( firing ) {
if ( i <= firingLength ) {
firingLength--;
if ( i <= firingIndex ) {
firingIndex--;
}
}
}
// Remove the element
list.splice( i--, );
// 如果是unique模式(这时不会有重复的函数),移除一次就可以了
if ( flags.unique ) {
break;
}
}
}
}
}
return this;
},
// 判断指定回调函数是否存在
has: function( fn ) {
if ( list ) {
var i = ,
length = list.length;
for ( ; i < length; i++ ) {
if ( fn === list[ i ] ) {
return true;
}
}
}
return false;
},
// Remove all callbacks from the list
empty: function() {
list = [];
return this;
},
// Have the list do nothing anymore
disable: function() {
list = stack = memory = undefined;
return this;
},
// Is it disabled?
disabled: function() {
return !list;
},
// Lock the list in its current state
lock: function() {
stack = undefined;
if ( !memory || memory === true ) {
self.disable();
}
return this;
},
// Is it locked?
locked: function() {
return !stack;
},
// Call all callbacks with the given context and arguments
fireWith: function( context, args ) {
if ( stack ) { // stack=[] 也是true
if ( firing ) {
if ( !flags.once ) {
stack.push( [ context, args ] );
}
} else if ( !( flags.once && memory ) ) {
fire( context, args );
}
}
return this;
},
// Call all the callbacks with the given arguments
fire: function() {
self.fireWith( this, arguments );
return this;
},
// To know if the callbacks have already been called at least once
fired: function() {
return !!memory; // 其实这个有问题, 当调用disable() 的时候 memory==undefined
}
}; return self;
}; })( jQuery );

下面是一些检验这些参数逻辑的代码:

      /*
jquery.Callbacks
*/
// var testUrl="http://www.runoob.com/try/ajax/demo_test.php";
// var callbacks=new jQuery.Callbacks("memory");
// callbacks.add(function(){alert("first callback")});
// callbacks.add(function(){alert("second callback")});
// callbacks.fire();
// memory
// callbacks.add(function(){alert("third callback")}); var callback2=
jQuery.Callbacks("once memory"), // once 表示回调函数列表只会fire一次,但是还会运行memory机制,也不限制回调函数列表里边有多个相同的函数(可以用unique 去重)
something = true;
function fn1(args)
{
alert('fn1 args:'+args);
console.log(this);
if(something){
callback2.fire(" test:第2次触发");
callback2.fire(" test:第3次触发"); //fire内部再触发的话 先放入stack中
something=false;
}
}
function fn2(){
alert('fn2');
}
callback2.add(fn1);
callback2.add(fn2); callback2.fire('测试:第1次触发');
callback2.fire('测试:第4次触发'); //once模式 只会fire一次, memory在add的时候促发
callback2.add(fn2);

源码地址

jQuery.callbacks 注释的更多相关文章

  1. jQuery.Callbacks之demo

    jQuery.Callbacks是jquery在1.7版本之后加入的,是从1.6版中的_Deferred对象中抽离的,主要用来进行函数队列的add.remove.fire.lock等操作,并提供onc ...

  2. jQuery回调、递延对象总结(上篇)—— jQuery.Callbacks

    前言: 作为参数传递给另一个函数执行的函数我们称为回调函数,那么该回调又是否是异步的呢,何谓异步,如:作为事件处理器,或作为参数传递给 (setTimeout,setInterval)这样的异步函数, ...

  3. jQuery.Callbacks 源码解读二

    一.参数标记 /* * once: 确保回调列表仅只fire一次 * unique: 在执行add操作中,确保回调列表中不存在重复的回调 * stopOnFalse: 当执行回调返回值为false,则 ...

  4. jQuery源代码学习之四——jQuery.callbacks

    自己实现的callbacks模块相较于jquery源代码中的callbacks模块有所简化,表面上看没有考虑firing这个参数,没有对之进行任何处理,即没有考虑在函数执行过程中,再次调用add,re ...

  5. jQuery.Callbacks之源码解读

    在上一篇jQuery.Callbacks之demo主要说了Callbacks对象初始化常见的选项,这一篇主要分析下Callbacks对象的源代码,对给出两个较为繁琐的demo // String to ...

  6. jQuery回调、递延对象总结(一)jQuery.Callbacks详解

    前言: 作为参数传递给另一个函数执行的函数我们称为回调函数,那么该回调又是否是异步的呢,何谓异步,如:作为事件处理器,或作为参数传递给 (setTimeout,setInterval)这样的异步函数, ...

  7. jQuery: Callbacks

    jQuery 中提供了一个Callback的工具类Callbacks,它提供了一个Callback Chain.使用它可以在一个chain上来执行相关操作.它也是jQuery中的ajax, Defer ...

  8. jquery.Callbacks的实现

    前言 本人是一个热爱前端的菜鸟,一直喜欢学习js原生,对于jq这种js库,比较喜欢理解他的实现,虽然自己能力有限,水平很低,但是勉勉强强也算是能够懂一点吧,对于jq源码解读系列,博客园里有很多,推荐大 ...

  9. jQuery 2.0.3 源码分析 回调对象 - Callbacks

    源码API:http://api.jquery.com/jQuery.Callbacks/ jQuery.Callbacks()是在版本1.7中新加入的.它是一个多用途的回调函数列表对象,提供了一种强 ...

随机推荐

  1. jstl <fmt:formatDate>标签

    <fmt:formatDate>标记用于在各种不同的方式来格式化日期 属性: <fmt:formatDate>标签具有以下属性: 属性 描述 必需 默认值 value 要显示的 ...

  2. Vue自定义指令和路由

    一.自定义指令 除了默认设置的核心指令( v-model 和 v-show ), Vue 也允许注册自定义指令. 下面我们注册一个全局指令 v-focus,该指令的功能是在页面加载时,元素获得焦点: ...

  3. 机器学习第4课:多变量线性回归(Linear Regression with Multiple Variables)

    4.1  多维特征 目前为止,我们探讨了单变量/特征的回归模型,现在我们对房价模型增加更多的特征, 例如房间数楼层等,构成一个含有多个变量的模型,模型中的特征为(x1,x2,...,xn).

  4. 第一章 初识shiro

    shiro学习教程来自开涛大神的博客:http://jinnianshilongnian.iteye.com/blog/2018936 第一章 初识shiro 简单了解shiro主要记住三张图即可. ...

  5. 2017.9.15 postgresql批量插入造成冲突后执行更新

    参考来自:https://stackoverflow.com/questions/40647600/postgresql-multi-value-upserts/46233907#46233907 1 ...

  6. xtrabackup详解

    xtrabackup是Percona公司CTO Vadim参与开发的一款基于InnoDB的在线热备工具,具有开源,免费,支持在线热备,备份恢复速度快,占用磁盘空间小等特点,并且支持不同情况下的多种备份 ...

  7. 局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍(转)

    局部敏感哈希(Locality-Sensitive Hashing, LSH)方法介绍 本文主要介绍一种用于海量高维数据的近似最近邻快速查找技术——局部敏感哈希(Locality-Sensitive ...

  8. js从$scope外部调用$scope内部函数,跨js调用非全局函数

    scope内部函数定义 //定位 $scope.LocateByPoint = function (x,y) { if(!x || !y) { window.alert("GPS坐标不存在, ...

  9. 清除掉AD的相关属性!

    今天有朋友问我怎么清除掉AD 的相关属性,由于他们的用户都设置了登录到属性,这样我们的用户就仅仅能登陆他须要设置的计算机.对于兴许规则的变更的时候,我们的管理员配置起来就比較复杂.他须要非常长的时间去 ...

  10. 设置VisualSVN在提交修改时必须输入一定数量的备注信息

    我发现在使用SVN中,提交时,很多人不习惯填写备注信息,虽然在培训中.平时使用时多次提醒备注信息的好处,但是效果不大,每次提交时还是不写,或者随便写两字. 所以很有必要通过系统设置强制填写足够数量的备 ...