jQuery版本 version = "1.11.1"
前言
$.Callbacks() 提供了一种强大的方法来管理回调函数队列,采用了观察者模式,通过add添加操作到队列当中,通过fire去执行这些操作。$.Callbacks是1.7版本从$.Deferred对象当中分离出来的,主要是实现$.Deferred功能。
$.Callbacks() 通过字符串参数的形式,提供四种可选参数。同时这些参数可以组合使用。
可选参数:
once | 确保回调列表只能被触发一次 |
memory | 缓存上一次fire时的参数值,当add()添加回调函数时,直接用上一次的参数值立刻调用新加入的回调函数 |
unique | 确保回调函数不能重复添加相同的函数 |
stopOnFalse | 某个回调函数返回false之后中断后面的回调函数 |
参数的处理
为了方便Callbacks内部对参数的判断,将传入的options参数进行处理。统一处理为Object的形式。
//正则表达式,用于匹配非空白符
var rnotwhite = (/\S+/g);
//存储options的对象
var optionsCache = {};
//根据字符串options创建对象
function createOptions( options ) {
var object = optionsCache[ options ] = {};
jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
object[ flag ] = true;
});
return object;
}
Query.Callbacks = function( options ) {
//将传入的字符串options转为对象
//首先检查cache中是否options对应对象
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
jQuery.extend( {}, options );
//省略
//省略
//省略
}
比如说 $.Callbacks('memory once'); options为字符串'memory once',处理之后的options为
{
memory:true,
once:true;
}
这样处理之后方便Callbacks对参数的判断。
jQuery.Callbacks()
源码
jQuery.Callbacks = function( options ) {
options = typeof options === "string" ?
( optionsCache[ options ] || createOptions( options ) ) :
jQuery.extend( {}, options );
var // Flag to know if list is currently firing
//回调列表是否正在执行中
firing,
// Last fire value (for non-forgettable lists)
//最近一次触发回调的参数
memory,
// Flag to know if list was already fired
//是否回调列表已近执行过至少一次
fired,
// End of the loop when firing
//执行过程的结尾
firingLength,
// Index of currently firing callback (modified by remove if needed)
//正在执行的回调函数的索引
firingIndex,
// First callback to fire (used internally by add and fireWith)
//初始执行的位置
firingStart,
// Actual callback list
//回调列表
list = [],
// Stack of fire calls for repeatable lists
//可重复的回调函数堆栈,用于控制触发回调时的参数列表
stack = !options.once && [],
// Fire callbacks
//触发回调函数列表
fire = function( data ) {
memory = options.memory && data;
fired = true;
firingIndex = firingStart || 0;
firingStart = 0;
firingLength = list.length;
firing = true;
for ( ; list && firingIndex < firingLength; firingIndex++ ) {
//执行回调列表中的函数,如果返回false且options.stopOnFalse 为true则停止回调列表的执行
if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
memory = false; // To prevent further calls using add
break;
}
}
firing = false;
if ( list ) {
if ( stack ) {
if ( stack.length ) {
//执行完毕之后,如果stack中有值。说明在回调列表正在执行的过程中,触发了fire。需要将另外的参数取出,再次执行回调列表。
fire( stack.shift() );
}
} else if ( memory ) {
list = [];
} else {
self.disable();
}
}
},
// Actual Callbacks object
//return 的对象
self = {
// Add a callback or a collection of callbacks to the list
// 回调列表中添加一个回调或回调的集合。
add: function() {
if ( list ) {
// First, we save the current length
var start = list.length;
(function add( args ) {
jQuery.each( args, function( _, arg ) {
var type = jQuery.type( arg );
if ( type === "function" ) {
if ( !options.unique || !self.has( arg ) ) {
list.push( arg );
}
} else if ( arg && arg.length && type !== "string" ) {
// Inspect recursively
add( arg );
}
});
})( 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
} else if ( memory ) {
firingStart = start;
fire( memory );
}
}
return this;
},
// Remove a callback from the list
//从回调列表中的删除一个回调或回调集合。
remove: function() {
if ( list ) {
jQuery.each( arguments, function( _, arg ) {
var index;
while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
list.splice( index, 1 );
// Handle firing indexes
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
//锁定当前状态的回调列表。
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 ];
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;
};
callbacks.add() | 回调列表中添加一个回调或回调的集合。 |
callbacks.remove() | 从回调列表中的删除一个回调或回调集合。 |
callbacks.has() | 确定列表中是否提供一个回调 |
callbacks.empty() | 从列表中删除所有的回调. |
callbacks.disable() | 禁用回调列表中的回调 |
callbacks.disabled() | 确定回调列表是否已被禁用。 |
callbacks.lock() | 锁定当前状态的回调列表。 |
callbacks.locked() | 确定回调列表是否已被锁定。 |
callbacks.fireWith() | 访问给定的上下文和参数列表中的所有回调。 |
callbacks.fire() | 用给定的参数调用所有的回调 |
callbacks.fired() | 回调是否已经被触发过至少一次 |
处理思路
once:
如果options.once=true;则stack=false; 如果回调列表已经被触发过至少一次,在fireWith中会直接返回,不会再触发内部fire函数。
memory:
如果options.memory=true;在触发回调列表的时候,memory会记录下最近一次fire传递的参数。在使用add添加回调的时候,如果memory为真则会直接触发添加的这些回调函数
unique:
如果options.unique=true;在使用add添加回调的时候,判断到回调列表中已经存在该函数,则不会将这个function添加进回调列表
stopOnFalse:
如果options.stopOnFalse=true;执行回调列表中的函数时,如果返回false且options.stopOnFalse 为true则停止回调列表的执行,跳出循环。