JQuery并没有简单的使用一个Array来存储回调函数,而是通过JQuery.Callbacks(options)返回一个self对象,此对象能够动态的add,remove和fire回调函数队列.此函数须要说明的是options參数,它是一个string,这个string由四个參数随意组合而成

options:
once:回调函数仅仅运行一次
memory:调用add时触发回调函数使用fire时传入的參数.
unique:回调函数仅仅能被加入到队列一次
stopOnFlase:有一个回调函数返回false,停止运行以下的回调函数.

JQuery.Callbacks(options)内的变量依据不同传參有不同的意思,这些变量由闭包引用扩大其生命周期,以在外部改变其值,下面进行说明
memory:假设options不包括'memory'字符串,memeory为false,其它为上一次fire(args)的參数.
fired:回调函数列表是否被触发过.
firing:回调函数列表是否正在被触发.为何要这个參数呢?由于假设在回调函数内调用了add,remove,fire 方法时会改变回调函数列表的状态(開始触发的位置,触发长度等等,这些是控制要运行回调函数列表中哪些函数的标志),此时其回调函数函数列表正在处于触发中,必须能够及时反映(修正触发位置,触发长度等等)回调函数列表的变化,以便在回调函数运行的循环中下一次迭代能够正确的触发回调函数列表.
firingStart:回调函数列表运行的開始位置.
firingLength:再运行几个回调函数
firingIndex:正在触发的函数在回调函数列表中的位置
list:存放回调函数
stack:假设在回调函数中调用fire或fireWith方法,将fire或fireWith传入的上下文和參数先入栈,稍后再用栈中的參数来作为參数运行回调函数中调用的fire或fireWidth。

注:不解的是走到stack.push分支时是在回调函数里调用fire或fireWidth,但这样会导致死循环,这个stack究竟怎么回事?还请明确的同学告知我一下。!

jQuery.Callbacks = function( options ) {

       // Convert options from String-formatted to Object-formatted if needed
// (we check in cache first)
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
jQuery.extend( {}, options ); var // Last fire value (for non-forgettable lists)
memory,
// Flag to know if list was already fired
fired,
// Flag to know if list is currently firing
firing,
// First callback to fire (used internally by add and fireWith)
firingStart,
// End of the loop when firing
firingLength,
// Index of currently firing callback (modified by remove if needed)
firingIndex,
// Actual callback list
list = [],
// Stack of fire calls for repeatable lists
// 假设没有配置once,stack为数组
// stack存放反复时fire參数
stack = !options.once && [],
// Fire callbacks
fire = function( data ) {
//memory 为false或fire时传入的參数
memory = options.memory && data;
fired = true;
//当前触发位置
firingIndex = firingStart || 0;
//触发回调函数队列的起始位置
firingStart = 0;
//待触发的回调函数队列长度
firingLength = list.length;
//正在触发标识设置为true
//仅仅有在Callbacks的回调函数里此值才会为true
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
//若配置了stopOnFalse当回调函数队列中函数返回值为false
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
//memory设置为false
memory = false; // To prevent further calls using add
//不再运行后面的回调函数
break;
}
}
//回调函数运行结束
firing = false;
if ( list ) {
//未配置once
if ( stack ) {
//运行在回调函数里调用的fire
if ( stack.length ) {
fire( stack.shift() );
}
//清空回调函数列表,但此callbacks仍可用
} else if ( memory ) {
list = [];
//让闭包的那些引用能够销毁
} else {
self.disable();
}
}
},
// Actual Callbacks object
self = {
// Add a callback or a collection of callbacks to the list
add: function() {
if ( list ) {
// First, we save the current length
// 将加入回调函数之前将当前callbacks的长度设为运行開始
var start = list.length;
( function add( args ) {
jQuery.each( args, function( _, arg ) {
var type = jQuery.type( arg );
if ( type === "function" ) {
// 假设未设置unique或者回调函数列表里没有此函数
// 在回调函数队列里加上此函数
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
// 假设arg是个类数组,再递归add
} else if ( arg && arg.length && type !== "string" ) {
// Inspect recursively
add( arg );
}
});
})( arguments );
// Do we need to add the callbacks to the
// current firing batch?
//在正在触发的回调函数中调用add方法会走此分支
if ( firing ) {
//立马反应要触发回调函数长度的改变
firingLength = list.length;
// With memory, if we're not firing then
// we should call right away
} else if ( memory ) {
//改变触发的開始位置为未加入前的回调队列长度
firingStart = start;
fire( memory );
}
}
return this;
},
// Remove a callback from the list
remove: function() {
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
//arg所在list的索引
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
//删除
list.splice( index, 1 );
// Handle firing indexes
//假设在回调函数里调用remove
if ( firing ) {
//要删除的回调函数是还没触发的
if ( index <= firingLength ) {
//触发的长度减一
firingLength--;
}
//要删除的是已经触发过的函数
if ( index <= firingIndex ) {
//正要触发索引减一
firingIndex--;
}
}
}
});
}
return this;
},
// Check if a given callback is in the list.
// If no argument is given, return whether or not list has callbacks attached.
has: function( fn ) {
return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
},
// Remove all callbacks from the list
empty: function() {
list = [];
firingLength = 0;
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
//锁住当前的状态,不会运行在回调函数里调用fire或fireWidth
lock: function() {
stack = undefined;
if ( ! memory ) {
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 ( list && ( !fired || stack ) ) {
args = args || [];
args = [ context, args.slice ? args.slice() : args ];
//?事实上这里有一点不解,走到这个分
//是在在回调函数里调通fire或fireWidth,但这样会导致死循环
if ( firing ) {
stack.push( args );
} else {
fire( 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 !!fired;
}
}; return self;
};

JQuery日记6.9 Promise/A之Callbacks的更多相关文章

  1. javascript异步代码的回调地狱以及JQuery.deferred提供的promise解决方式

    我们先来看一下编写AJAX编码常常遇到的几个问题: 1.因为AJAX是异步的,全部依赖AJAX返回结果的代码必需写在AJAX回调函数中.这就不可避免地形成了嵌套.ajax等异步操作越多,嵌套层次就会越 ...

  2. jquery源码分析(四)——回调对象 Callbacks

    借用百度百科来说明下回调函数: 回调函数就是一个通过函数指针调用的函数.如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数.回调函数不是由该 ...

  3. JQuery日记6.7 Javascript异步模型(二)

    异步模型看起来非常美,但事实上它也是有天生缺陷的.看以下代码 try { setTimeout( function(){ throw new Error( '你抓不到我的!' ); }, 100); ...

  4. JQuery日记_5.13 Sizzle选择器(六)选择器的效率

        当选择表达式不符合高速匹配(id,tag,class)和原生QSA不可用或返回错误时,将调用select(selector, context, results, seed)方法,此方法迭代DO ...

  5. JQuery日记6.5 Javascript异步模式(一)

    理解力JQuery前实现异步队列,有必要理解javascript异步模式. Javascript异步其实并不严重格异步感,js使某些片段异步方式在将来运行,流不必等待继续向下进行. 在多线程的语言中最 ...

  6. JQuery日记 5.11 Sizzle选择器(五)

    //设置当前document和document相应的变量和方法 setDocument = Sizzle.setDocument = function( node ) { var hasCompare ...

  7. JQuery日记 5.31 JQuery对象的生成

    JQuery对象的生成 1 selector为不论什么可转换false的空值   返回空JQuery对象 2 selector为字符串   2.1 selector为html字符串或有id属性的标签 ...

  8. JQuery日记_5.14 Sizzle选择器(七)

    上篇说道,tokenize方法会把selector切割成一个个selector逻辑单元(如div>a是三个逻辑单元 'div','>','a')并为之片段赋予相应类型的过滤函数. for ...

  9. Jquery AJAX如何使用Promise/Deferred实现顺序执行?

    有的时候有我有N个AJAX请求,第下个请求可能要依赖上个请求的返回值, 可以用 $.ajax("test1.php").then(function(data) { // data ...

随机推荐

  1. WIN7 Wireshark: There are no interfaces on which a capture can be done

    有的时候我们在Windows7的环境下使用Wireshark的时候,比如点击[Interface List]的时候,出现错误. 错误内容如下: There are no interfaces on w ...

  2. 何谓Dandy?它是一种着装风格

    何谓Dandy?它是一种着装风格_女性_腾讯网 何谓Dandy?它是一种着装风格 2012年02月17日09:47腾讯专稿我要评论(0) 字号:T|T   何谓Dandyism?它是一种风格,词根Da ...

  3. 借贷宝推广得现金是真的_注册就送人民币20元_邀请码CRJYQTK

    动动手指,20元立即到手.即优步uber打车和滴滴专车豪投数亿元争夺专车市场之后,一款名为借贷宝的APP推广在网上流传开来,目前主要看重的就是它的推广力度,豪投20亿让大众来推广.简单流程:下载借贷宝 ...

  4. Hibernate映射1

    Hibernet映射 集合映射: 类的属性字段是集合的. set: <set name=”属性字段” table=“属性字段的表名”> <key 外键 column=“”> & ...

  5. Android得到一个闹钟在第三方

    收集报警信息 闹铃时间,闹铃备注信息 闹铃引起系统变化的点: 1. Send Notification (正点闹钟能够设置不发送) 2. Play audio 闹铃信息结构体 ClockInfo{ S ...

  6. android卸载反馈实现

    博客原地址:http://blog.csdn.net/wang_shaner/article/details/41543787 实现原理 fork分叉函数 fork分叉(分裂)函数可以创建一个新进程, ...

  7. 修改Chrome的User Agent的方法 真实有效

    如何修改Chrome的User Agent: 通过网络上查找,修改Chrome的Usre Agent有3种方式,但有的方式是不起作用的. 给Chrome添加启动参数(有作用) 通过扩展-User-Ag ...

  8. win7下安装Ubuntukylin-14.04双系统

    工具准备: 下载ISO系统镜像,UltraISO,EasyBCD,分区助手,8G 优盘 U盘启动制作流程: 1,打开分区助手,从硬盘中分出空闲空间(60G)作为Ubuntu工作空间,文件系统设为Ext ...

  9. css渐变/背景

    1.线性渐变(gradient变化) linear-gradient线性渐变指沿着某条直线朝一个方向产生渐变效果. 上图是从黄色渐变到绿色 background:linear-gradient( to ...

  10. 《think in python》学习-7

    think in python 7 迭代 对一个变量可以进行多次赋值 是合法的. 例如以下: bruce = 5 print bruce bruce = 7 print bruce 因为有了多重赋值 ...