文档章节

关于jQuery.Callbacks

 琅玕
发布于 2015/09/29 14:37
字数 1749
阅读 4
收藏 0

一、 jQuery.Callbacks(args) 

说到Deferred对象首先就要说说 jQuery.Callbacks,Deffered是基于Callbacks实现的。jQuery.Callbacks()返回一个链式工具对象用于管理一系列的回调函数,它支持添加、移除、触发、锁定与禁用回调函数

1、首先我们解释一下参数args,参数args是可选的,在不传入的情况下表示回调的列表中的函数可以被多次触发,如果要传入参数的情况下args支持以下四种标记

参数args所支持的标记
once 表示回调列表中的函数只能被触发一次
memory 记录上一次触发回调函数列表时的参数,之后添加的任何回调函数会立即执行并且将上次记录的参数传入
unique 确保回调函数列表中函数值唯一的无重复的
stopOnFalse 当某个回调函数返回false时中断执行,之后的函数将不再执行
2、我们在看看callbacks返回回调列表含有哪些方法
callbacks.remove( callbacks ) 从回调函数列表中移除一个或一组回调函数
callbacks.has callbacks ) 检测指定的函数时候在回到函数列表中
callbacks.empty(  ) 清空回调函数列表
callbacks.disable( callbacks ) 禁用回调函数列表
callbacks.disabled( callbacks ) 判断回调函数列表是否被禁用
callbacks.lock( callbacks ) 锁定回调函数列表
callbacks.locked( callbacks ) 判断回调函数列表是否被锁定
callbacks.fireWith( callbacks ) 使用指定的上下文和参数去触发回调函数列表所有的函数
callbacks.fire( callbacks ) 使用指定参数去触发回到函数中所有的函数
callbacks.fired( callbacks ) 判断回调函数是否被触发过

3、源码分析

源码中只对add, fire, fireWith做了简单的注释,说实话我并没有100%理解,至于其他方法比较简单就不做注释了

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 用法比较复杂
		// memory == undeinfed 回调函数列表未调用或已被禁用
		// memory == [ context, args ] 说明回调函数列表已经被调用以下场景
		// 1) memory + !stopOnFalse模式 2) memory + stopOnFalse + 回调中不存在return false的情况
		// memory == true 已被触发 出现在以下场景
		// 1)非memory 模式 2) stopOnFalse + 回调中存在return false
		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
		// 如果是once模式,stack设置为false否则为空数组
		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++ ) {
			//	console.log( data[ 0 ], data[ 1 ] );
				// 上下文
				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
		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 ) {
						// 遍历self.add传入的参数
						jQuery.each( args, function( _, arg ) {
							var type = jQuery.type( arg );
							if ( type === "function" ) {
								// 如果是type是函数且不是唯一模式或列表中不存在arg
								// 就将arg放入list中
								if ( !options.unique || !self.has( arg ) ) {
									list.push( arg );
								}
							} else if ( arg && arg.length && type !== "string" ) {
								// Inspect recursively
								// 如果arg是数组,那么递归调用add 继续遍历
								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 ) {
						// 如果是memory模式立即用上次执行过的参数与上下文立即
						// 从从上次最后一个回调下标开始执行回调函数列表
						// 比如memory 模式下回调中有3个并且已经执行过
						// 当再次add的时候就会立刻用上次的上下文与参数执行当前添加的
						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中
						stack.push( args );
					} else {
						fire( args );
					}
				}
				return this;
			},
			// Call all the callbacks with the given arguments
			fire: function() {
				// 用当前的对象调用fireWith
				self.fireWith( this, arguments );
				return this;
			},
			// To know if the callbacks have already been called at least once
			fired: function() {
				return !!fired;
			}
		};

	return self;
};


下面我们结合实例说明

1)不传入任何参数的情况下

var callbacks = jQuery.Callbacks(), bool = true, count = 1;

var fun = function( args ) {
    console.log( 'fun', args );
    ++count;
    if ( bool ) {
        callbacks.fire('第'+count+'次触发');
        if( count > 99 ) bool = false;
    }    
}

callbacks.add(fun);
callbacks.fire('第'+count+'次触发')

此例中fun会被触发100次

2) once模式,且不是memory模式 当执行后就是禁用回调函数,其实就是将list赋值为了undefined

var callbacks = jQuery.Callbacks('once');

var fun = function (args) {
	console.log( 'fun', args );
}

callbacks.add(fun);
callbacks.fire('once模式');
console.log( callbacks.disabled() ) // => true

3)如果是once+stopOnFalse模式,且某个回调返回了false

var callback = jQuery.Callbacks('once stopOnFalse');

var fun1 = function (args) {
	console.log( 'fun1', args );
	return false;
}

var fun2 = function (args) {
	console.log( 'fun2', args );
}

callback.add(fun1);
callback.add(fun2);
callback.fire('once+stopOnFalse');
console.log( callback.disabled() ) //

这个例子中当执行了fun1后就会禁用之后的所有回调

4)once + memory 模式 Deferred中所使用的方式,第一次fire就会将list = [], 并且memory 等于第一次执行的上下文以及参数,当第二次add的时候会直接会用上次上下文以及参数即fire(memory)

var callback = jQuery.Callbacks('once memory');

var fun1 = function (args) {
	console.log( 'fun1', args );
	return false;
}

var fun2 = function (args) {
	console.log( 'fun2', args );
}

var fun3 = function (args) {
	console.log( 'fun3', args );
}


callback.add(fun1);
callback.fire('once+memory');
callback.add(fun2);
callback.add(fun3);


© 著作权归作者所有

粉丝 0
博文 1
码字总数 1749
作品 0
杭州
私信 提问
jQuery Deferred对象源码分析

jQuery Deferred对象源码分析 知行合一,止于至善2018-01-092 阅读 WEB开发 $.Deferred() 是一个工厂方法,返回的是一个添加了实现各种操作的Object对象。 内部是通过deferred = {};然后添加...

知行合一,止于至善
2018/01/09
0
0
jquery.Callbacks的实现

功能介绍 jq的Callbacks模块主要是为其他模块提供服务的,他就像一个温柔的小女人,在背后默默地付出。Deferred就像一个巨人,在jq中那么的突出,但在内部,他受到Callbacks的服务。 Callba...

技术小阿哥
2017/11/27
0
0
jQuery源码解析之$().animate()(上)

前言: 需要先看 jQuery源码解析之.queue()、.dequeue()和jQuery.Callbacks() 一、举例 的宽度先变成 500px,再变成 300px,最后变成 1000px: 二、().animate() 作用: 通过 CSS 样式将元素...

进击的小进进
06/27
0
0
jQuery源码解析之$.queue()、$.dequeue()和jQuery.Callbacks()

前言: 方法和方法是为 jQuery 的动画服务的,目的是为了允许一系列动画函数被异步调用,但不会阻塞程序。 所以这篇是为jQuery的动画解析做准备的。 一、.queue()、.dequeue() 和 .queue()、...

进击的小进进
06/23
0
0
关于本博客数据仓库方面的原创文章汇总

关于本博客数据仓库方面的原创文章汇总 收藏 关于数据仓库方面的文章汇总 我的数据仓库之路! 关于数据仓库维度处理的系列文章 1 关于数据仓库维度数据处理的方法探究系列—— 维的概述 2 关...

baoqiangwang
2018/06/26
0
0

没有更多内容

加载失败,请刷新页面

加载更多

启动参数

常用启动参数,通过 -Dxx.yy=zz注入应用参数 -Deureka.instance.metadata-map.starkGroup=test3 -Dserver.port=8989 本地调试过程中,可改变端口来启动多个相同服务。修改启动的VM参数即可...

ZH-JSON
5分钟前
3
0
ES配置修改

查看配置 GET /_cluster/settings 修改配置 PUT /_cluster/settings{ "persistent" : { "xpack" : { "monitoring" : { "collection" : { "enabled" : ......

messud4312
17分钟前
2
0
Spring事务传播属性有那么难吗?看这一篇就够了

Spring事务传播属性有那么难吗?看这一篇就够了 笔者文笔功力尚浅,如有不妥,请慷慨指出,必定感激不尽 学习东西要知行合一,如果只是知道理论而没实践过,那么掌握的也不会特别扎实,估计过...

不学无数的程序员
17分钟前
2
0
VMware vSphere ESXi主机的访问控制

在vShpere中,访问ESXi主机的途径很多,如下: ESXi DCUI ESXi Shell ESXi SSH ESXi Host Client vCenter --> vSphere web client / vSphere Client VMware vSphere ESXi主机的访问控制,除了......

大别阿郎
42分钟前
4
0
大神讲解CGI、FastCGI和PHP-FPM关系图解

参考资料 概念了解:CGI,FastCGI,PHP-CGI与PHP-FPM:http://www.nowamagic.net/librarys/veda/detail/1319 php中fastcgi和php-fpm是什么东西:https://www.zybuluo.com/phper/note/50231 ......

网络小虾米
51分钟前
5
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部