jQuery.Callbacks()回调函数队列用法详解
本文实例讲述了jQuery.Callbacks()回调函数队列用法。分享给大家供大家参考,具体如下:
1、jQuery.Callbacks
ThejQuery.Callbacks()function,introducedinversion1.7,returnsamulti-purposeobjectthatprovidesapowerfulwaytomanagecallbacklists.Itsupportsadding,removing,firing,anddisablingcallbacks.
The$.Callbacks()functionisinternallyusedtoprovidethebasefunctionalitybehindthejQuery$.ajax()and$.Deferred()components.Itcanbeusedasasimilarbasetodefinefunctionalityfornewcomponents.
接下来,我们分别看下四个标准的控制标志。
1.1once
创建的callbacks对象只允许被fireWith()一次[注意:方法fire()是fireWith()的外观模式]。
varcallbacks=$.Callbacks("once");
callbacks.add(function(){console.log("f1");});
callbacks.fire();//输出"f1"
callbacks.fire();//什么也不发生,在源码中已经禁用了list.disable()
1.2memory
在调用add()方法时,如果这时callbacks队列满足fired&&firing=false(真执行完毕)&&memory(需要在构造函数指定),那么add()进去的回调函数会立即执行,而这个add进去的回调函数调用时的参数存储在memory变量中。memory变量用于存储最后一次调用callbacks.fireWith(...)时所使用的参数[context,arguments]。
IftheCallbacksobjectiscreatedwiththe"memory"flagasitsargument,additionalfunctionsmaybeaddedandfiredafterthecallbacklistislocked.
$(function($){
varcallbacks=$.Callbacks("memory");
callbacks.add(function(){console.log("f1");});
callbacks.fire();//输出"f1",这时函数列表已经执行完毕!
callbacks.add(function(){console.log("f2");});//memory作用在这里,没有fire,一样有结果:f2
callbacks.fire();//重新触发一次,输出f1f2。firingStart=0
//与once一起使用
callbacks=$.Callbacks("oncememory");
callbacks.add(function(){console.log("f3");});
callbacks.fire();//输出"f3",这时函数列表已经执行完毕!
callbacks.add(function(){console.log("f4");});//没有fire,一样有结果:f4
callbacks.fire();//由于为"once",这里将什么也不执行
});
1.3unique
回调函数列表中的函数是否可以重复,该特性与add()方法有关,可以避免在回调函数列表中加入多个相同回调函数。
varf1=function(){console.log("f1");};
varcallbacks=$.Callbacks();
callbacks.add(f1);
callbacks.add(f1);
callbacks.fire();//输出f1f1
//传递参数"unique"
callbacks=$.Callbacks("unique");
callbacks.add(f1);//有效
callbacks.add(f1);//添加不进去
callbacks.fire();//输出:f1
1.4stopOnFalse
默认情况下,当执行fireWith()方法时,整个回调函数列表中的所有函数都会顺序执行,但如果设置了stopOnFalse,那么当某个函数返回false时,后边的函数将不再执行。即使设置了memory,再次添加的函数也不会执行了,即一旦某个函数返回false的情况下,会禁用memory功能。但如果没设置”once”,再次调用fire可以重新触发该callbacks。
varf1=function(){console.log("f1");returnfalse};//注意returnfalse;
varf2=function(){console.log("f2");};
varcallbacks=$.Callbacks();
callbacks.add(f1);
callbacks.add(f2);
callbacks.fire();//输出f1f2
callbacks=$.Callbacks("memorystopOnFalse");
callbacks.add(f1);
callbacks.add(f2);
callbacks.fire();//只输出f1
callbacks.add(function(){console.log("f3");});//不会输出,memory已经失去作用了
callbacks.fire();//重新触发,输出f1
2.memory回调队列
vari=0;
varinc=function(s){
i++;
alert(i+"$"+s);
};
varcallbacks=$.Callbacks('memory');
callbacks.add(functioniteral(){
callbacks.add(inc);
if(i<=1){
callbacks.fire(i);
}
});
callbacks.fire(i);
callbacks.add(inc);
/*
list=[];
list=[it];
--->fire(0),i=0
1、list=[it,inc]
2、push(fire(0))
3、i++[inc(0)](i=1)
shift()--->fire(0),i=1
1、list=[it,inc,inc];
2、push(fire(1)),
3、i++[inc(0)]
4、i++[inc(0)](i=3)
shift()--->fire(1),i=3
1、list=[it,inc,inc,inc];
2、i++[inc(1)]
3、i++[inc(1)]
4、i++[inc(1)](i=6)
--->add(inc),i=6,memory=[this,1]
1、i++[inc(1)](i=7)
*/
3、jQuery.CallBacks源码
说明:为了便于理解,修改了部分源码,减少了一些功能~~~
jQuery.Callbacks=function(options){
//string-->object改进建议:将未配置的参数缺省为false,而不是undefined。便于程序阅读和控制.
options=optionsCache[options]||createOptions(options);
varfiring,
memory,//Lastfirevalue[context,args](formemorylists)
fired,
firingLength,
firingIndex,
firingStart,
list=[],
stack=options.once===true?false:[],//Stackoffirecallsforrepeatablelists
fire=function(data){//data-->[context,args]
memory=!!options.memory&&data;//falseOR[context,arguments]
fired=true;
firingIndex=firingStart||0;
firingStart=0;
firingLength=list.length;
firing=true;
//这里list放在条件判断中是因为执行回调函数可能会改变list的状态,比如this.disable()。
for(;list&&firingIndex<firingLength;firingIndex++){
if(list[firingIndex].apply(data[0],data[1])===false&&options.stopOnFalse===true){
memory=false;//禁止memory功能,这样调用add()增加新回调函数不会立即自动调用
break;
}
}
firing=false;
if(list){
if(stack){
//进入条件:fired&&firing===false&&stack,实现递归调用
if(stack.length){
fire(stack.shift());//[[context1,arguments1],[context2,arguments2]]
}
}elseif(memory){
//进入条件:fired&&firing===false&&stack===undefined&&有memory字段(memory变量只能通过fire()函数修改)
//这里的list=[],主要是用于性能优化,以防该对象长时间不执行,占用系统内存
list=[];
}else{
//进入条件:fired&&firing===false&&stack===undefined&&没有memory字段,说明必要继续保留的必要
self.disable();
}
}
},
self={
add:function(){
if(list){//几乎所有API都应该绑定这个条件,因为我们需要处理队列
varoriginLength=list.length;
jQuery.each(arguments,function(_,arg){
if(jQuery.type(arg)==="function"){
//(!(options.unique&&self.has(arg)))unique字段的作用
if(!options.unique||!self.has(arg)){
list.push(arg);
}
}
});
if(firing===true){
//进入条件:说明正在执行回调函数队列中,而当前执行的这个回调函数激活了add()函数,及时维护循环边界
firingLength=list.length;
}elseif(memory){
//进入条件:memory&&fired&&firing===false,说明之前的fire()行为已经完全结束
firingStart=originLength;
fire(memory);
}
}
returnthis;
},
remove:function(){
if(list){
jQuery.each(arguments,function(_,arg){
varlastIndex;
while((lastIndex=jQuery.inArray(arg,list,lastIndex))>=0){
list.splice(lastIndex,1);
if(firing===true){//及时更新边界条件,实现智能处理
if(lastIndex<=firingLength){
firingLength--;
}
if(lastIndex<=firingIndex){
firingIndex--;
}
}
}
});
}
returnthis;
},
has:function(func){//这个API有两个功能,根据单一职责角度来说,应该增加一个isNotEmpty()接口(非空)
returnfunc?jQuery.inArray(func,list)>-1:!!(list&&list.length);
},
empty:function(){
list=[];
returnthis;
},
disable:function(){//彻底禁用该对象,stack禁用,memory禁用
list=stack=memory=undefined;
returnthis;
},
disabled:function(){
return!list;
},
lock:function(){
stack=undefined;
//如果memory没有存储调用状态,直接禁用这个对象(可能是从未调用就被锁定,或者没有memory字段)
if(!memory){
self.disable();
}
returnthis;
},
locked:function(){
return!stack;
},
fireWith:function(context,args){
args=args||[];
vardata=[context,args];
if(list&&(fired===false||stack)){
if(firing){
//进入条件:firing===true&&stack说明当前正在执行回调函数队列
stack.push(data);//stack其实是一个队列结构,这里用stack有些混淆
}else{
//进入条件一:firing===false&&fired===false说明从来没有fire()过
//进入条件二:firing===false&&fired===true&&stack=[]说明至少调用过一次,而且当前允许多次调用,可以通过lock()锁定
fire(args);
}
}
returnthis;
},
fire:function(){
self.fireWith(this,arguments);
returnthis;
},
fired:function(){
return!!fired;
}
};
returnself;
};
4、胡思乱想
jQuery.Callbacks()方法的核心是fire()方法,将该fire()方法被封装在函数中不可直接访问,因此像memory、firing、fired这些状态对于外部上下文来说是不可更改的。
还有需要注意的是,如果回调函数中使用了this对象,可以直接用这个this来访问self对象的公有API。当然,也可以用fireWith()自己指定this的引用对象。
jQuery.Callbacks()的核心思想是Pub/Sub模式,建立了程序间的松散耦合和高效通信。
更多关于jQuery相关内容感兴趣的读者可查看本站专题:《jQuery常用插件及用法总结》、《jquery中Ajax用法总结》、《jQuery表格(table)操作技巧汇总》、《jQuery拖拽特效与技巧总结》、《jQuery扩展技巧总结》、《jQuery常见经典特效汇总》、《jQuery动画与特效用法总结》及《jquery选择器用法总结》
希望本文所述对大家jQuery程序设计有所帮助。