jQuery源码分析 Callbacks

本文深入解析jQuery中的Callbacks方法,探讨其如何通过观察者模式管理回调函数队列,并介绍其核心功能及参数选项。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

jQuery版本 version = "1.11.1"
 

前言


$.Callbacks() 提供了一种强大的方法来管理回调函数队列,采用了观察者模式,通过add添加操作到队列当中,通过fire去执行这些操作。$.Callbacks是1.7版本从$.Deferred对象当中分离出来的,主要是实现$.Deferred功能。


$.Callbacks()  通过字符串参数的形式,提供四种可选参数。同时这些参数可以组合使用

可选参数:

 

once确保回调列表只能被触发一次
memory缓存上一次fire时的参数值,当add()添加回调函数时,直接用上一次的参数值立刻调用新加入的回调函数
unique确保回调函数不能重复添加相同的函数
stopOnFalse

某个回调函数返回false之后中断后面的回调函数

 

参数的处理

为了方便Callbacks内部对参数的判断,将传入的options参数进行处理。统一处理为Object的形式。

//正则表达式,用于匹配非空白符
var rnotwhite = (/\S+/g);

//存储options的对象
var optionsCache = {};

//根据字符串options创建对象
function createOptions( options ) {
	var object = optionsCache[ options ] = {};
	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
		object[ flag ] = true;
	});
	return object;
}

Query.Callbacks = function( options ) {

	//将传入的字符串options转为对象
	//首先检查cache中是否options对应对象
	options = typeof options === "string" ?
		( optionsCache[ options ] || createOptions( options ) ) :
		jQuery.extend( {}, options );
	//省略
	//省略
	//省略
}

 比如说 $.Callbacks('memory once'); options为字符串'memory once',处理之后的options为

{

memory:true,

once:true;

}

这样处理之后方便Callbacks对参数的判断。

 

jQuery.Callbacks()

源码

jQuery.Callbacks = function( options ) {

	options = typeof options === "string" ?
		( optionsCache[ options ] || createOptions( options ) ) :
		jQuery.extend( {}, options );

	var // Flag to know if list is currently firing
	    //回调列表是否正在执行中
		firing,
		// Last fire value (for non-forgettable lists)
		//最近一次触发回调的参数
		memory,
		// Flag to know if list was already fired
		//是否回调列表已近执行过至少一次
		fired,
		// End of the loop when firing
		//执行过程的结尾
		firingLength,
		// Index of currently firing callback (modified by remove if needed)
	    //正在执行的回调函数的索引
		firingIndex,
		// First callback to fire (used internally by add and fireWith)
		//初始执行的位置
		firingStart,
		// Actual callback list
		//回调列表
		list = [],
		// Stack of fire calls for repeatable lists
		//可重复的回调函数堆栈,用于控制触发回调时的参数列表
		stack = !options.once && [],
		// Fire callbacks
		//触发回调函数列表
		
		
		fire = function( data ) {
			memory = options.memory && data;
			fired = true;
			firingIndex = firingStart || 0;
			firingStart = 0;
			firingLength = list.length;
			firing = true;
			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
				//执行回调列表中的函数,如果返回false且options.stopOnFalse 为true则停止回调列表的执行
				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
					memory = false; // To prevent further calls using add
					break;
				}
			}
			
			firing = false;
			if ( list ) {
				if ( stack ) {
					if ( stack.length ) {
						//执行完毕之后,如果stack中有值。说明在回调列表正在执行的过程中,触发了fire。需要将另外的参数取出,再次执行回调列表。
						fire( stack.shift() );
					}
				} else if ( memory ) {
					list = [];
				} else {
					self.disable();
				}
			}
		},
		// Actual Callbacks object
		
		//return 的对象
		self = {
			// Add a callback or a collection of callbacks to the list
			// 回调列表中添加一个回调或回调的集合。
			add: function() {
				if ( list ) {
					// First, we save the current length
					var start = list.length;
					(function add( args ) {
						jQuery.each( args, function( _, arg ) {
							var type = jQuery.type( arg );
							if ( type === "function" ) {
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} 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;
					// With memory, if we're not firing then
					// we should call right away
					} else if ( memory ) {
						firingStart = start;
						fire( memory );
					}
				}
				return this;
			},
			// Remove a callback from the list
			//从回调列表中的删除一个回调或回调集合。
			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;
			},
			// Check if a given callback is in the list.
			// If no argument is given, return whether or not list has callbacks attached.
			//确定列表中是否提供一个回调
			has: function( fn ) {
				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
			},
			// Remove all callbacks from the list
			// 从列表中删除所有的回调.
			empty: function() {
				list = [];
				firingLength = 0;
				return this;
			},
			// Have the list do nothing anymore
			//禁用回调列表中的回调
			disable: function() {
				list = stack = memory = undefined;
				return this;
			},
			// Is it disabled?
			// 确定回调列表是否已被禁用。 
			disabled: function() {
				return !list;
			},
			// Lock the list in its current state
			//锁定当前状态的回调列表。
			lock: function() {
				stack = undefined;
				if ( !memory ) {
					self.disable();
				}
				return this;
			},
			// Is it locked?
			//确定回调列表是否已被锁定。
			locked: function() {
				return !stack;
			},
			// 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;
			}
		};

	return self;
};

 

callbacks.add()

 回调列表中添加一个回调或回调的集合。

callbacks.remove() 

 从回调列表中的删除一个回调或回调集合。
callbacks.has() 确定列表中是否提供一个回调

callbacks.empty() 

从列表中删除所有的回调.

callbacks.disable()  

禁用回调列表中的回调
callbacks.disabled() 确定回调列表是否已被禁用。 

callbacks.lock()  

锁定当前状态的回调列表。

callbacks.locked()  

  确定回调列表是否已被锁定。

callbacks.fireWith() 

访问给定的上下文和参数列表中的所有回调。

callbacks.fire() 

用给定的参数调用所有的回调

callbacks.fired() 

回调是否已经被触发过至少一次

 

处理思路

once:

如果options.once=true;则stack=false; 如果回调列表已经被触发过至少一次,在fireWith中会直接返回,不会再触发内部fire函数。

memory:

如果options.memory=true;在触发回调列表的时候,memory会记录下最近一次fire传递的参数。在使用add添加回调的时候,如果memory为真则会直接触发添加的这些回调函数

unique

如果options.unique=true;在使用add添加回调的时候,判断到回调列表中已经存在该函数,则不会将这个function添加进回调列表

stopOnFalse

如果options.stopOnFalse=true;执行回调列表中的函数时,如果返回false且options.stopOnFalse 为true则停止回调列表的执行,跳出循环。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值