Callbacks是JQ的一个回调对象,可以对回调进行统一的管理。而且还为Deferred延迟对象提供了基础功能。
function aa(){ alert(1); } function bb(){ alert(2); } setTimeout(function(){ aa(); },100); bb();
var ck= $.Callbacks();//Callbacks对象 function aa(){ alert(1); } function bb(){ alert(2); } ck.add(bb); //添加进list数组 setTimeout(function(){ aa(); ck.fire(); //触发 },100);这样代码就会先执行aa(),然后执行bb();
当执行$.Callbacks()时,我们看源码
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 );
(1)once
fire()只触发一次
var ck= $.Callbacks("once"); function aa(){ alert(1); } function bb(){ alert(2); } ck.add(aa,bb); ck.fire(); ck.fire();以上只触发了一次fire()事件。
(2)memory
记忆功能,记住fire(),如果在fire()触发之后,再继续添加回调,那么直接执行函数。
var ck= $.Callbacks("memory"); function aa(){ alert(1); } function bb(){ alert(2); } ck.add(aa); ck.fire(); ck.add(bb);
这里fire事件触发后,先执行了aa(),ck.add(bb)之后,bb()函数立即触发。如果,没有"memory",那么bb()是不会执行的
(3)unique
每个函数只会添加一次,不会有重复。
var ck= $.Callbacks("unique"); function aa(){ alert(1); } function bb(){ alert(2); } ck.add(aa); ck.add(aa); ck.fire();
(4)stopOnFalse
当添加的函数中返回false时,中止fire事件。
var ck= $.Callbacks("stopOnFalse"); function aa(){ alert(1); } function bb(){ alert(2); return false; } ck.add(bb); ck.add(aa); ck.fire();
bb()函数会执行,aa()不会执行。
// Convert String-formatted options into Object-formatted ones and store in cache function createOptions( options ) { var object = optionsCache[ options ] = {}; jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) { object[ flag ] = true; }); return object; }optionsCache是缓存对象。
createOptions函数会把 “memory once”这样的options入参变成:object.memory=true;object.once=true;这会在源码中用到。
调用Callbacks函数返回:
return self;
我们看源码,发现self是一个对象。
// Actual Callbacks object self = { add: function() {}, remove: function() {}, fireWith:function(){}, ...... } }
add: function() { if ( list ) { //list初始化为[],所以会进入if // First, we save the current length var start = list.length; (function add( args ) { //这里使用了匿名自执行,并且传入add()方法的参数对象arguments,这里我对于为什么使用匿 名自执行感觉不太理解,感觉完全没有必要,使用了之后,参数的作用域链变长了,也不需要避免向全局作用域写参数??? jQuery.each( args, function( _, arg ) {//调用each方法,为args里面的每一个参数绑定一个匿名函数,匿名函数里 面的第一个参数 _ 是索引,第二个参数arg是具体的某一项的值或者引用 var type = jQuery.type( arg ); if ( type === "function" ) { //如果传进来的是函数进入if if ( !options.unique || !self.has( arg ) ) { //如果在Callbacks没有传入unique或者列表list 中没有没有arg,进入if list.push( arg ); } } else if ( arg && arg.length && type !== "string" ) { //适用于ck.add(aa,bb,cc);的情况 // Inspect recursively add( arg ); } }); })( arguments ); if ( firing ) { firingLength = list.length; // With memory, if we're not firing then // we should call right away } else if ( memory ) { //如果Callbacks函数中传入了memory,那么后面再add进来的函数直接触发fire事件 firingStart = start; fire( memory ); } } return this; },
当执行ck.fire()时,我们先回触发self.fire()事件。
fire: function() { self.fireWith( this, arguments ); return this; },
fireWith: function( context, args ) { if ( list && ( !fired || stack ) ) { //stack = !options.once && [] 这个不需要解释了吧!没有once或者没有执行guofire事件就为true args = args || []; args = [ context, args.slice ? args.slice() : args ]; //context为self对象,args.slice数组拷贝 if ( firing ) { //如果这时正在执行fire事件,我们暂时把这些将要触发的函数,存到stack中。 stack.push( args ); } else { //否则,直接触发函数 fire( args ); } } return this; },
self.fireWith()调用内部的fire函数
fire = function( data ) { memory = options.memory && data; //有memory其有要执行的函数 fired = true; //fired标记置为true firingIndex = firingStart || 0; firingStart = 0; firingLength = list.length; firing = true; //正在触发fire事件 for ( ; list && firingIndex < firingLength; firingIndex++ ) { if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {//data[0]就是self,执行函数list[index],如果执行的函数返回了false并且有stopOnFalse,进入if memory = false; // To prevent further calls using add //把memory置为false,并且跳出循环,不再继续触发。 break; } } firing = false; if ( list ) { if ( stack ) {//如果stack中存着函数引用, if ( stack.length ) { fire( stack.shift() );//触发stack存储的函数 } } else if ( memory ) {如果有memory list = []; } else { self.disable();//没有memory,后续不再触发fire函数 } } },