jQuery源码学习(版本1.11)-Callbacks

13 篇文章 0 订阅

概述

本文详细分析jquery-1.11.1.js源码文件行数:3048~3248;
代码简介:定义了工具函数callbacks,用于创建Callbacks对象,Callbacks对象可添加异步回调函数,对他们的执行进行统一管理;
下文进行详细代码分析。

jQuery.Callbacks

// 匹配非空白
var rnotwhite = (/\S+/g);

// 缓存已经建立过的参数组合
var optionsCache = {};

// 将建立Callbacks对象传入的参数String,转成对象使用并且缓存
function createOptions( options ) {
	var object = optionsCache[ options ] = {};
	// 使用match将options分割开,match到的非空白字符串构成数组,执行回调后转成boolean放进object
	jQuery.each( options.match( rnotwhite ) || [], function( _, flag ) {
		object[ flag ] = true;
	});
	return object;
}

// Callbacks
jQuery.Callbacks = function( options ) {

	// 将参数转成对象使用,先判断缓存中是否已有
	options = typeof options === "string" ?
		( optionsCache[ options ] || createOptions( options ) ) :
		jQuery.extend( {}, options );

	var // list里的回调是否正在执行的标志
		// 个人认为,主要是考虑list里的函数可能会操作Callbacks对象本身
		firing,
		// 最后执行过fire的上下文和参数数据
		memory,
		// 判断list是否已经执行过的标志
		fired,
		// list的长度
		firingLength,
		// list正在执行的函数位置
		firingIndex,
		// list开始执行的位置
		firingStart,
		// 回调函数列表
		list = [],
		// 这是多用途的变量,可重复触发时,为数组,保存firing过程中,list的函数又调fire去执行的其他函数,如果设置了once,则会为false,就会用于阻止触发
		stack = !options.once && [],
		// 调用回调函数
		fire = function( data ) {
			memory = options.memory && data;
			fired = true;
			firingIndex = firingStart || 0;
			firingStart = 0;
			firingLength = list.length;
			// list执行前设置firing状态
			firing = true;
			for ( ; list && firingIndex < firingLength; firingIndex++ ) {
				// options.stopOnFalse为true且回调返回false时,list停止
				if ( list[ firingIndex ].apply( data[ 0 ], data[ 1 ] ) === false && options.stopOnFalse ) {
					// 走进分支说明options.stopOnFalse为true且执行结果出现了false,设置memory,保证之后add添加进来的函数不会再触发
					memory = false; 
					break;
				}
			}
			// list执行完毕设置firing状态
			firing = false;
			if ( list ) {
				// stack存在说明可重复触发
				if ( stack ) {
					// length大于0则说明保存了没触发的函数的参数,取出并且递归调用fire
					// 由于前面firingIndex和firingLength很好的保存了list现在的已执行状态的函数的位置,因此递归调用只会执行新增的函数
					if ( stack.length ) {
						fire( stack.shift() );
					}
				} else if ( memory ) {
					list = [];
				// disable掉对象,阻止重复触发
				} else {
					self.disable();
				}
			}
		},
		// Callbacks实际返回的对象
		self = {
			// 添加回调,可传单个或多个
			add: function() {
				if ( list ) {
					// First, we save the current length
					var start = list.length;
					(function add( args ) {
						//使用each对每个回调执行操作
						jQuery.each( args, function( _, arg ) {
							var type = jQuery.type( arg );
							if ( type === "function" ) {
								// unique没设置或者设置了但arg不在list里,则可添加
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} else if ( arg && arg.length && type !== "string" ) {
								// arg不是function,但存在length表示类数组,则调用递归,相当于躺平数组
								add( arg );
							}
						});
					})( arguments );
					// 如果list正在执行,则重设firingLength长度,因为list这时候变长了
					if ( firing ) {
						firingLength = list.length;
					// 如果memory不为空,则需要立即执行新增的函数
					} else if ( memory ) {
						firingStart = start;
						fire( memory );
					}
				}
				return this;
			},
			// 删除回调
			remove: function() {
				if ( list ) {
					jQuery.each( arguments, function( _, arg ) {
						var index;
						while ( ( index = jQuery.inArray( arg, list, index ) ) > -1 ) {
							list.splice( index, 1 );
							// 处理firing的场景(说明回调函数里调用了remove,避免list后面的回调发生混乱)
							if ( firing ) {
								if ( index <= firingLength ) {
									firingLength--;
								}
								if ( index <= firingIndex ) {
									firingIndex--;
								}
							}
						}
					});
				}
				return this;
			},
			// 使用inArray判断fn是否已经加进list
			has: function( fn ) {
				return fn ? jQuery.inArray( fn, list ) > -1 : !!( list && list.length );
			},
			// 清空所有回调
			empty: function() {
				list = [];
				firingLength = 0;
				return this;
			},
			// disable功能
			disable: function() {
				list = stack = memory = undefined;
				return this;
			},
			// 返回使能状态
			disabled: function() {
				return !list;
			},
			// 锁住对象
			lock: function() {
				stack = undefined;
				if ( !memory ) {
					self.disable();
				}
				return this;
			},
			// 是否已锁
			locked: function() {
				return !stack;
			},
			// 可传自定义上下文和参数去执行list里的函数
			fireWith: function( context, args ) {
				if ( list && ( !fired || stack ) ) {
					args = args || [];
					args = [ context, args.slice ? args.slice() : args ];
					// 判断是否正在执行,firing为true只能说明正在执行的回调里面又对Callbacks对象进行了操作
					if ( firing ) {
						// 先将参数保存在stack里,最后再执行
						stack.push( args );
					} else {
						fire( args );
					}
				}
				return this;
			},
			// 调用保存起来的回调函数,传入的参数会作为回调函数的参数
			fire: function() {
				self.fireWith( this, arguments );
				return this;
			},
			// Callbacks对象是否已经至少fire过一次
			fired: function() {
				return !!fired;
			}
		};

	return self;
};


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值