jQuery 源码callbacks

callbacks工具方法,作用是函数回调的统一管理

jQuery.Callbacks = function( options ) {
		
}


使用:类似于事件绑定,fire之后,之前绑定的方法,都执行。
观察者模式。

	function aaa()  {
        alert(1);
    }
    function bbb() {
        alert(2);
    }
    function ccc() {
        alert(3)
    }

    var cb = $.Callbacks();
    cb.add(aaa);
    cb.add(bbb);
    cb.add(ccc);

    cb.fire();		// 弹出了 1 和 2, 3


    add(fun)-->List添加方法。
    fire对list数组,进行for循环执行。

 /**********************************************************/
    function aaa() {
	    alert(1);
	}

	(function () {

	    function bbb() {
	        alert(2);
	    }

	})();


	aaa();
	bbb();
	//这里无法同时执行弹出1 和 2,因为无法进行统一作用域的管

 /**********************************************************/


	// 但是Callbacks可以搞定,这个问题。
	var cb = $.Callbacks();

	function aaa() {
	    alert(1);
	}
	cb.add(aaa);

	(function () {

	    function bbb() {
	        alert(2);
	    }

	    cb.add(bbb);

	})();

	cb.fire();	// 只需要一句就可以了。触发所有

	//这里只要回调对象时全局的, 就可以随时向回调函数中添加函数,而后执行。


 /**********************************************************/



jQuery.Callbacks = function( options ) 


options配置参数。四个!!!

 *	once:			will ensure the callback list can only be fired once (like a Deferred)
 *
 *	memory:			will keep track of previous values and will call any callback added
 *					after the list has been fired right away with the latest "memorized"
 *					values (like a Deferred)
 *
 *	unique:			will ensure a callback can only be added once (no duplicate in the list)
 *
 *	stopOnFalse:	interrupt callings when a callback returns false

Callbacks的四个参数。

var cb = $.Callbacks();
cb.fire();	
cb.fire();	//fire可以执行多次触发的。


(1)once:代表,fire只能触发一次。
	cb.fire();	
	cb.fire();	//不会执行。
让fire执行一次就好了

(2)memory:
    var cb = $.Callbacks();
    function aaa() {
        alert(1);
    }
    cb.add(aaa);

    cb.fire();

    function bbb() {
        alert(2);
    }
    cb.add(bbb);

   //这段代码执行过后,只能fire出1,不能执行bbb函数


	var cb = $.Callbacks('memory');
	function aaa() {
	    alert(1);
	}
	cb.add(aaa);

	cb.fire();

	function bbb() {
	    alert(2);
	}
	cb.add(bbb);

	//这段代码就是会打印出1 2 。后面的2也可以触发,只要添加就可以执行。

	memory是作用到add上面,然后再调用fire。

    var cb = $.Callbacks('memory');
    function aaa() {
        alert(1);
        return false;
    }
    cb.add(aaa);

    cb.fire();

    function bbb() {
        alert(2);
    }
    
    setTimeout(function () {
         cb.add(bbb);
    }, 1000);

我想了一个例子,应该可以讲的明白,如果变量里面定义了memory,作为初始化,
那么,就执行。当你调用了fire以后,再向内添加add函数的时候,就直接继续执行。
					



(3)unique:去重复,让函数具有唯一性。作用于add

	var cb = $.Callbacks();
	function aaa() {
	    alert(1);
	}
	cb.add(aaa);
	cb.add(aaa);
	cb.fire();
	//这里触发2次

	var cb = $.Callbacks('unique');
	function aaa() {
	    alert(1);
	}
	cb.add(aaa);
	cb.add(aaa);
	cb.fire();
	//这里触发1次,重复的函数名,不能放入list,


(4)stopOnFalse
	
	var cb = $.Callbacks('stopOnFalse');
	function aaa() {
	    alert(1);
	    return false;
	}
	cb.add(aaa);

	function bbb() {
	    alert(2);
	}
	cb.add(bbb);

	cb.fire();
	//这里只是执行了alert(1)。而alert(2),并没有背执行
	//这个变量作用于fire中,判断函数中是否返回false,如果返回false,就立刻推出list循环。

当然还可以接受到组合的形式,比如,memory和once组合的形式,通过空格来分隔开的。

	var cb = $.Callbacks('once stopOnFalse');

Callbacks方法:

add:			将函数,push入 list 中。
remove:			删除
has				检测是否有这个函数,返回false/true
empty			清空数组
disable			全部锁住。禁止,不执行。
lock 			锁住。stack=undefined		
locked			判断是否锁住
fireWith
fire:			--》调用的是fireWith. --》fire = function(data);
fired  			判断是否fired



list = [], 用了保存函数列表。

add 添加。
			add: function() {
				if ( list ) {
					// First, we save the current length
					var start = list.length;
					(function add( args ) {
						//这里支持传入多个,cb.add(aaa, bbb);
						jQuery.each( args, function( _, arg ) {
							var type = jQuery.type( arg );
							if ( type === "function" ) {
								//判断是不是唯一。unique!!!
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} 
							//支持数组形式, cb.add([aaa, bbb]);
							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;

					//有merory就直接执行。
					} else if ( memory ) {
						firingStart = start;
						fire( memory );
					}
				}
				return this;
			},

支持这个:

cb.add(aaa);
cb.add(aaa, bbb);
cb.add([aaa, bbb]);


remove:删除。
对数组进行遍历删除。splice

		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;
			},

cb.add(aaa);
cb.add(bbb);
cb.add(ccc);

cb.remove(bbb);
cb.fire();		// 就只有aaa 和 ccc


fire:执行。

		fire = function( data ) {
			memory = options.memory && data;
			fired = true;
			firingIndex = firingStart || 0;
			firingStart = 0;
			firingLength = list.length;
			firing = true;		//触发开始
			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
					memory = false; // To prevent further calls using add
					break;
				}
			}
			firing = false;		//触发结束
			
			if ( list ) {		//判断list
				if ( stack ) {
					if ( stack.length ) {	//stack的长度部位空,
					//递归调用
						fire( stack.shift() );	//将栈中的第一个返回。并且fire
					}
				} 
				//如果有记忆,
				else if ( memory ) {
					//列表清空
					list = [];
				} else {
					self.disable();
				}
			}
		},

		//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;
		}



stack = !options.once && [],	//这里定义了一个栈

firing 事件触发的时候。
		

fireWith:
		fireWith: function( context, args ) {
			if ( list && ( !fired || stack ) ) {
				args = args || [];
				args = [ context, args.slice ? args.slice() : args ];
				
				//这里,如果是firing时,就讲fire压入栈
				if ( firing ) {	
					stack.push( args );
				} else {
					fire( args );
				}
			}
			return this;
		},

有个例子

var cb = $.Callbacks();

var singal = true;
function aaa() {
	alert(1);

	if (singal) {
		cb.fire();		//stack.push( args );
		singal = false;
	}
}

cb.add(aaa);

function bbb () {
	alert(2);
}
cb.add(bbb);

cb.fire();


弹出顺序是1,2 1,2.
	这个是在fire中实现的。

			if ( list ) {		//判断list
				if ( stack ) {
					if ( stack.length ) {	//stack的长度部位空,
					//递归调用
						fire( stack.shift() );	//将栈中的第一个返回。并且fire
					}
				} 
				//如果有memory的时候,就清空数组。
				else if ( memory ) {
					//列表清空
					list = [];
				} else {
					self.disable();
				}
			}
原文地址:https://www.cnblogs.com/hgonlywj/p/4852964.html