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. idea编译工程时出现Error:java: 无效的目标发行版: 1.8

    见图,从上述可以看出工程用的jdk1.7,而idea编译时采用的是1.8版本(应该idea新版本内置的jre是1.8吧,默认编译采用1.8) 修改:如下图    http://blog.csdn.ne ...

  2. c++一些面试题目

    1.What is achieved by prefixing the 'static' keyword to a file-level function or file-level variable ...

  3. VMware虚拟机三种网络模式的区别(上篇)

    提到VMware大家就想起了虚拟机技术,虚拟机技术在最近的几年中得到了广泛的发展,一些大型网络服务商都开始采用虚拟机技术,不仅节省了投资成本,更节约了能源的消耗. 我们知道VMware也分几种版本,普 ...

  4. uva 10382 Watering Grass_贪心

    题意:给你个矩形n*m,再给你n个圆的圆心坐标和半径,问最用最少用几个圆把这个矩形覆盖 思路:直接想发现这问题不容易,后来发现可以把圆看做区间(能把矩形面积覆盖),然后这个问题就容易解决了 #incl ...

  5. OpenStack cloudCompute glassary术语project,tenant,user

    1,tenantA group of users, used to isolate access to Compute resources(一组用户,用于隔离访问计算资源). An alternati ...

  6. 求职(2015南京站获得百度、美的集团、趋势科技、华为offer)

    版权所有所有:没有马缰绳chhuach(CSDN博客源).转载请注明出处. 禁止www.haogongju.net转载. 特此声明 一.开篇: 9月底,找工作接近尾声,笔者主要经历了2015年南京站百 ...

  7. 响应式流布局插件DyLay

    jQuery插件-Dylay,流布局我们前面介绍过很多,但这个流布局jQuery插件不同的是它的动画效果很不错,大家可以尝试使用下.另外<有用的jQuery布局插件推荐>这篇文章中有好几个 ...

  8. vsts

     首先要搞清楚啥是VSTS,这对于我们安装配置有基础作用.看看这张组织结构图就一目了然了.Visual Studio Team Suite就是我们常说的VS.NET 2005开发环境,安装包3G左右的 ...

  9. sqlserver数据库三范式的理解

    从来都是听过概念,过一段时间就忘记了,根本就没有深入的理解.这次梳理一遍,用自己的方式记录一下. 1nf 原子性,不可拆分性 例如一张表里包含一个class属性(软件系,外语系,经贸系...)字段,这 ...

  10. C++中的namespace

    本文转载来自:http://blog.csdn.net/yao_zhuang/article/details/1853625 namespace中文意思是命名空间或者叫名字空间,传统的C++只有一个全 ...