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

猜你喜欢

转载自schifred.iteye.com/blog/2315217