JQuery源码浅析: Callbacks

1.定义

  回调这个词对每个js使用者是如此的熟悉不过. 从字面看很容易理解,Callback就是对调,Callbacks就是多个回掉.在JQuery中就是回调队列, 也就是Callbacks中保存着很多个回调函数队列, 也就是按照顺序执行(按照加入队列的顺序触发这些函数,并不意味着第一个运行结束才调用第二个回调,因为js中存在异步)队列中的每一个回调函数. 我们也可以这么理解,也就是我们常说的事件订阅和发布模式. 说道事件,我们就容易理解了.每一次trigger就对调用一个回调函数.

  那么Callbacks有什么用呢?在JQuery中,Deffered中使用Callbacks实现了Promise/A+标准. 解决异步的同步问题,解决代码深层嵌套.


2.Callbacks中的主要方法

callbacks.add()        回调列表中添加一个回调或回调的集合。
callbacks.disable()    禁用回调列表中的回调
callbacks.disabled()   确定回调列表是否已被禁用。 
callbacks.empty()      从列表中删除所有的回调.
callbacks.fire()       用给定的参数调用所有的回调
callbacks.fired()      访问给定的上下文和参数列表中的所有回调。 
callbacks.fireWith()   访问给定的上下文和参数列表中的所有回调。
callbacks.has()        确定列表中是否提供一个回调
callbacks.lock()       锁定当前状态的回调列表。
callbacks.locked()     确定回调列表是否已被锁定。
callbacks.remove()     从回调列表中的删除一个回调或回调集合。
3.主要参数

    options = {  
        once:       回调对象仅触发(fire)一次  
     
        memory:     若true,在Callbacks正则触发事件过程中,新加入回调函数,新加入的函数将在旧的回调函数队列执行完成之后,促发新加入的.
     
        unique:     在add操作中,相同的函数仅只一次被添加(push)到回调列表中  
     
        stopOnFalse:当回调函数返回false,中断列表中的回调循环调用,且memory === false,阻止在add操作中将要触发的回调  
    } 
4.源码
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 );

	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
		//触发队列, 多次触发的队列才把触发的上下文入栈
		//(同一个时间只有一次触发队列执行,也就是说连续触发fire两次队列,第一次执行完,才会执行第二次[第一次触发,第二次触发...])
		stack = !options.once && [],
		// Fire callbacks
		//触发回调函数, self使用函数fire实现最终的回调函数的调用
		fire = function( data ) {
			//如果是memory类型管理器, 记住fire的事件data,以便下次add的时候可以重新fire这个事件
			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 ) {
				if ( stack ) {
					//如果触发队列中还有等待执行的触发
					if ( stack.length ) {
						fire( stack.shift() );//
					}
				} else if ( memory ) {
					list = [];
				} else {
					self.disable();
				}
			}
		},
		// Actual Callbacks object
		//var cb = $.Callbacks();返回的实际是self对象, 在JQuery中很多这样的使用.使用闭包实现开闭和封装.
		//有点类似Java中的内部类,例如使用内部类Iterator 实现对容器的遍历.通过类提供的接口,限制访问实际外部类的东西.
		//self作为Callbacks的对外接口,我们使用它来访问Callbacks
		self = {
			// Add a callback or a collection of callbacks to the list
			add: function() {
				if ( list ) {
					// First, we save the current length
					//记录本次触发的队列长度位置,当是memory的时候可以接着触发新加入的回调函数
					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 || [];
					//栈中存的上下文格式是[上下文(默认self为上下文), [参数1, 参数2...]]
					args = [ context, args.slice ? args.slice() : args ];
					//触发回调队列的时候,如果上一次触发还正在进行,那么久把当前触发的上下文和参数保存到栈stack中,
					//这样, 上一次触发回调完成之后,可以从栈中取出上下文和参数,接着触发下一次
					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;
			}
		};
	//返回self
	return self;
};



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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值