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程序设计有所帮助。