Callbacks源码
var callbacks=$.Callbacks(options) 创建实例
options.once 是否只执行一次,默认为否
options.memory:是否记录上次执行的回调函数参数,记录后,再次执行回调时将该参数推入queue参数数组中,默认为否
options.unique:保证回调函数的单一性,默认为否
options.stopOnFalse:当回调返回值为否时,是否终止回调函数执行,默认为否
配置项可以用字符串输入,将自动转化为对象形式,如"once"将转化为{once:true}
callbacks.add(fn) 添加回调函数
callbacks.fire("foo") 将参数"foo"传给各回调函数,并触发回调函数执行
callbacks.fireWith(content,“foo”) 回调函数上下文设为content,参数为"foo",并触发回调函数执行
callbacks.has(fn) 回调函数数组list是否有函数fn
callbacks.empty() 清空回调函数数组list
callbacks.remove(fn) 清除回调函数数组list指定的回调函数fn
callbacks.disable() 使回调函数中add和fireWith、fire方法均不可用,清空回调函数列表list、参数列表queue
callbacks.disabled() 判断实例是否不可用
callbacks.lock() 使回调函数中add方法均不可用,fireWith、fire方法根据memory有无设置有效性,若无且执行状态为不在执行中,fireWith、fire方法不可用
callbacks.lock() 判断实例是否锁死
源码书写的长处:
利用循环语句实现回调函数的顺序执行
利用循环语句+数组方法起始查询位清空数组中的重复项
利用转换类型的方式卡死if条件判断,进而阻止函数执行,如list回调函数列表在disable方法执行时设为"",而非[],使其在add方法的条件返回否值,阻止add方法执行
通过闭包驻留缓存信息如list回调函数数组、queue参数数组、memory前次执行参数记录等
源码:
define([
"./core",
"./var/rnotwhite"// 返回匹配空白的正则
], function( jQuery,rnotwhite ){
// 当options为字符串时,使用match方法分割空格类字符,各数组项作为object的属性,赋值为true后返回
function createOptions(options){
var object={};
jQuery.each( options.match( rnotwhite )||[], function(_,flag){
object[flag]=true;// 空数组不执行该语句
} );
return object;
}
/*
* Create a callback list using the following parameters:
*
* options: an optional list of space-separated options that will change how
* the callback list behaves or a more traditional option object
*
* By default a callback list will act like an event callback list and can be
* "fired" multiple times.
*
* Possible options:
*
* once:是否只执行一次,默认为否
* memory:是否记录上次执行的回调函数参数,记录后,再次执行回调时将该参数推入queue参数数组中,默认为否
* unique:保证回调函数的单一性,默认为否
* stopOnFalse:当回调返回值为否时,是否终止回调函数执行,默认为否
*/
jQuery.Callbacks=function(options){
// 将字符串格式的options转化成对象形式
options=typeof options==="string" ? createOptions(options) : jQuery.extend({},options);
var firing,// 回调函数正在执行中状态
memory,// 前次执行时回调函数使用的参数
fired,// 回调函数已执行状态
locked,// 锁定回调函数,回调函数数组清空
list=[],// 所有回调都添加到list数组列表中
queue=[],// 数组形式存储回调函数的参数,每个数组项又是数组形式,其中首项为this,即Callbacks对象
firingIndex=-1,// 用以指向list回调函数数组的序号,便于循环执行回调
// 内部函数,执行回调
fire=function(){
locked=options.once;
fired=firing=true;
for ( ; queue.length; firingIndex=-1 ){
memory=queue.shift();
while ( ++firingIndex<list.length ){// 利用循环语句使回调函数顺序执行
if ( list[firingIndex].apply(memory[0], memory[1])===false && options.stopOnFalse ){
firingIndex=list.length;
memory=false;
}
}
}
// 在不记录前次执行回调函数参数的前提下,当memory中的参数已执行,则将memory置为否
if ( !options.memory ){
memory=false;
}
firing=false;
// once设为真,只执行一次的前提下,清空回调函数数组
if ( locked ){
if ( memory ){
list=[];
}else{
list="";// memory为否,即options.memory为否,此时add方法失效
}
}
},
self={
// 添加回调函数
add:function(){
if ( list ){
if ( memory && !firing ){
firingIndex=list.length-1;// 重新设置firingIndex的意义???
queue.push(memory);
}
(function add(args){
jQuery.each(args,function(_,arg){
if ( jQuery.isFunction(arg) ){
if ( !options.unique || !self.has(arg) ){
list.push(arg);
}
}else if( arg && arg.length && jQuery.type(arg)!=="string" ){
// 递归添加回调函数
add(arg);
}
} );
})(arguments);
if ( memory && !firing ){// options.memory设为真,且没有回调函数执行的前提下,执行回调函数
fire();
}
}
return this;
},
// 从list列表清除某些回调函数
remove:function(){
jQuery.each(arguments, function(_,arg){
var index;
// 利用循环语句查找list回调函数数组中与arg函数相同的项
while ( ( index=jQuery.inArray(arg,list,index) ) > -1 ){
list.splice(index,1);
if ( index<=firingIndex ){// 影响当前执行的Callbacks实例中的回调函数,函数删除后序号减1
firingIndex--;
}
}
} );
return this;
},
// 传入参数时判断函数是否list回调函数数组中,否则判断list中是否有回调函数
has:function(fn){
return fn ? jQuery.inArray(fn,list)>-1 : list.length>0;
},
// 清空回调函数
empty: function(){
if ( list ){
list=[];
}
return this;
},
// locked设为[],list设为"",使add、fireWith方法失效
disable: function(){
locked=queue=[];
list=memory="";
return this;
},
// 返回当前实例的fire、add方法是否有效,locked判断fire方法可能有效
disabled: function(){
return !list;
},
// fire方法执行后,执行lock方法,清空参数队列,且locked设为[],使fireWith方法无效(需要locked为否)
// 当memory和firing均为否时,list置为"",使add方法无效(需要list为否)
lock: function(){
locked=queue=[];
if ( !memory && !firing ) {
list=memory="";
}
return this;
},
// 返回当前实例是否被锁定,参数数组queue或回调函数数组list被清空
locked: function(){
return !!locked;
},
// 执行回调函数,queue数组首项为Callbacks构造函数,其余项为给回调函数的参数
fireWith: function(context, args){
if ( !locked ) {
args=args||[];
args=[context, args.slice?args.slice():args];
queue.push(args);
if ( !firing ){
fire();
}
}
return this;
},
// 执行回调函数,arguments以数组形式传给各回调函数
fire: function(){
self.fireWith(this,arguments);
return this;
},
// 返回回调函数是否被调用
fired: function(){
return !!fired;
}
};
return self;
};
return jQuery;
});