6.jQuery.Deferred相关

简介:

由于jQuery.Defferred本身是基于jQuery.Callback的,所以,需要对jQuery.Callback有一定地了解才行。

Deferred相关功能,用于延迟对象,实现对异步的统一管理(其实,本质还是Callback)。代码框架如下:

jQuery.extend({
    Deferred: function( func ) {
    },
    when: function(subordinate){
    }
});

可以看出就是为jQuery添加了Deferred、when两个属性方法。通过调用这两个方式实现对异步的统一管理。

代码详解:

Deferred:

变量:

可以从源码中看出来,Deferred声明了tuples、state、promise、deferred这四个变量

var tuples = [
		[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
		[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
		[ "notify", "progress", jQuery.Callbacks("memory") ]
	],
	state = "pending",
	promise = {
		state: function() {
			return state;
		},
		always: function() {
		},
		then: function() {
		},
		promise: function( obj ) {
		}
	},
	deferred = {};
  • tuples:一个二维数组,元素是数组,元素数组内的元素组成是,字符串、字符串、jQuery.Callback对象、可能存在的字符串(前两个元素数组存在第四个元素)。
  • state:字符串,"pending"。
  • promise:一个对象,内部初始化了四个属性,都是函数。
  1. state函数直接返回state字符串
  2. promise函数,传入一个对象,如果存在的话,就调用jQuery.extend,将promise的各个属性赋值给对象。不存在的话,就直接返回promise。
  3. always、then:涉及到之后的函数,先不讲。
  • deferred:一个没有属性的空对象。

之后将promise的then属性赋值给promise的pipe属性。(可以延长函数地执行,和then内部的执行有关)

promise.pipe = promise.then

jQuery.each:

使用jQuery.each对二维数组tuples进行遍历操作。i是数组下标,tuple是二维数组内的元素数组。

jQuery.each( tuples, function( i, tuple ) {
});

创建了两个变量,list是jQuery.Callbacks()返回的对象,stateString是代表状态的字符串。

var
    list = tuple[ 2 ],
    stateString = tuple[ 3 ];

可以看出,promise.done、promise.fail、promise.progress这三个函数,本质上还是jQuery.Callbacks中的add函数。

promise[ tuple[1] ] = list.add;

如果stateString存在的话(即数组有第四个元素),为list添加三个函数,

  1. 执行的时候将state改为stateString(即tuple[3])
  2. 将另外一个的callback销毁,(list = stack = memory = undefined)(因为存在第四个元素的数组只有两个,而0 ^ 1=1,1 ^ 1=0)
  3. 将第三个的callback锁住。(因为是有memory的,所以只是将stack设为undefined)
if ( stateString ) {
	list.add(function() {
		state = stateString;
	}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
}

这段代码中的大致作用就是,当第一个和第二的数组中的callback执行(fire())的时候,将另外一个的callback销毁,同时锁住第三个数组的callback。

为deferred添加属性:

deferred的resolve、reject、notify属性,就是一个函数,就是对应地执行resolveWith、rejectWith、notifyWith,并且传入参数this(会根据不同的条件改变,很简单,就不细说了)和arguments。

而对应地resolveWith、rejectWith、notifyWith,本是上就是为对应的callback调用fireWith。

deferred[ tuple[0] ] = function() {
	deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
	return this;
};
deferred[ tuple[0] + "With" ] = list.fireWith;

结尾:

promise.promise( deferred );
if ( func ) {
	func.call( deferred, deferred );
}

将promise地对象,全部复制给defered。

如果使用jQuery.Deferred地时候,传入了函数元素,就执行该函数,this是deferred,参数也是deferred。

之前的promise.always、promise.then

由之前的代码,可以知道,Deferred其实就是内部创建了三个jQuery.Callbacks,根据不同的属性方法进行触发,(resolve、done一组、reject、fail一组、notify、progress一组,都对应callback的fire和add)。

promise.always

always: function() {
	deferred.done( arguments ).fail( arguments );
	return this;
},

always,使用done和fail添加函数(两个callback中的list都有了这个函数),说明可以由resolve、reject任意一个触发。

(因为callback中的add是返回this的,在这里就是deffered,所以执行一个函数之后,直接再通过属性继续执行)

promise.then

then: function( /* fnDone, fnFail, fnProgress */ ) {
	var fns = arguments;
	return jQuery.Deferred(function( newDefer ) {
		jQuery.each( tuples, function( i, tuple ) {
			var action = tuple[ 0 ],
				fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
			// deferred[ done | fail | progress ] for forwarding actions to newDefer
			deferred[ tuple[1] ](function() {
				var returned = fn && fn.apply( this, arguments );
				if ( returned && jQuery.isFunction( returned.promise ) ) {
					returned.promise()
						.done( newDefer.resolve )
						.fail( newDefer.reject )
						.progress( newDefer.notify );
				} else {
					newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
				}
			});
		});
		fns = null;
	}).promise();
},
  • 将参数赋值给fns变量。
  • 使用jQuery.Deferred,传入一个函数(其实就就是执行了结尾的func.call),其中函数的this和参数newDefer就都会是deferred。
  • 然后使用jQuery.each遍历tuples,i是下标,tuple是元素。action是代表执行的字符串,fn则是传入的参数数组中下标与i对应的元素(在这里可以知道,传入then的参数函数,第一个与resolve组对于,第二个与reject组对应,第三个与notify组对应)
  • 然后就是调用deferred,使用对应的tuple[1](done、fail、progress,本质上都是add),添加函数到对应的callback中的lst中。
  • 添加的函数内部,首先创建returned变量,returned接收参数fn或者是fn.apply( this, arguments )的执行结果(then中的函数被触发后,就在这里执行了。不过,arguments用来接收触发的时候传进来的数组)
  • 这里的代码内容用于pipe了(很少用,可以不管,我也比较迷糊,只是大致地理解了一下),如果returned存在,且returned.promise是函数的话,就使用done、fail、progress加载函数;不过不是的话,之前的函数的返回结果可以作为参数会传递到新的函数中。
  • 将fns赋值给null,释放内存。
  • 最好执行promise(),由于没有参数传入,就会返回promise。

when:

Deferred是基于callback之上的,when则是基于Deferred之上的,是对多个Deferred进行管理,可以大致的理解为,使用Deferred管理多个Deferred。

when中的Deferred都触发过了,才会执行。

变量:

var i = 0,
	resolveValues = core_slice.call( arguments ),
	length = resolveValues.length,
	// the count of uncompleted subordinates
	remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,
	// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
	deferred = remaining === 1 ? subordinate : jQuery.Deferred(),
	// Update function for both resolve and progress values
	updateFunc = function( i, contexts, values ) {
		return function( value ) {
			contexts[ i ] = this;
			values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
			if( values === progressValues ) {
				deferred.notifyWith( contexts, values );
			} else if ( !( --remaining ) ) {
				deferred.resolveWith( contexts, values );
			}
		};
	},
	progressValues, progressContexts, resolveContexts;

resolveValues:代表参数的数组(core_slice.call( arguments )相当于arguments.slice(),将参数数组这个类数组,彻底传转化为数组)。

length:输入参数的数量。

remaining:当输入的参数只有一个的且不为函数或者不存在的话,返回0,其他情况返回数组长度本身。功能是计数器,用于计算传进来的Deferred还有几个没被触发。

deferred:当remaining的长度为一的时,返回参数subordinate,反之则返回jQuery.Deferred()。功能是用于管理传入的多个Deferred的Deferred。

updateFunc:函数,接受三个参数,i是执行函数的下标,contexts是代表作用域的合集(很明显,在这里可以看到,只是做个样子,表示一下,其实还是this),values代表被管理的Deferred合集数组

返回一个函数,接收参数value。开始先将contexts[ i ]赋值this,values[ i ]赋值为value,如果value长度大于一,就转化数组。如果values等于progressValues(这是个空数组,而在后面加载时,传入的也是progressValues),就执行notifyWith;反之,如果remaining为1的话,执行触发resolveWith(是1的,算上这一次,就相当于都执行过了)。

progressValues、progressContexts、resolveContexts:创建还没初始化。

触发的判断:

// add listeners to Deferred subordinates; treat others as resolved
if ( length > 1 ) {
	progressValues = new Array( length );
	progressContexts = new Array( length );
	resolveContexts = new Array( length );
	for ( ; i < length; i++ ) {
		if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
			resolveValues[ i ].promise()
				.done( updateFunc( i, resolveContexts, resolveValues ) )
				.fail( deferred.reject )
				.progress( updateFunc( i, progressContexts, progressValues ) );
		} else {
			--remaining;
		}
	}
}
// if we're not waiting on anything, resolve the master
if ( !remaining ) {
	deferred.resolveWith( resolveContexts, resolveValues );
}

遍历,根据条件resolveValues,将deferred的参数加载到每个被管理的Deferred:

  • done:配合updateFunc,表示只有全部都resolve,才会触发when的deferred的notifyWith
  • fail:只要reject过一次,就会触发when的deferred的reject
  • progress:配合updateFunc,只要执行了notify,就会触发when的deferred的resolveWith

最后,如果 !remaining 判定过了(表示之前就已经执行过了)

小结:

jQuery2.0.3源码本身具有一定复杂性,以及我自身的限制,还做不到一目了然很简单地表述出来,所以,本文有一定地障碍和门槛,可能会有些费劲。

这个只是根据其中的一些情况分析解读(因为我也有点烦躁了,所以不是很全面详细),离真正的掌握,还是有点距离的。

源码:3043行--------3183行

jQuery.extend({

	Deferred: function( func ) {
		var tuples = [
				// action, add listener, listener list, final state
				[ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
				[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
				[ "notify", "progress", jQuery.Callbacks("memory") ]
			],
			state = "pending",
			promise = {
				state: function() {
					return state;
				},
				always: function() {
					deferred.done( arguments ).fail( arguments );
					return this;
				},
				then: function( /* fnDone, fnFail, fnProgress */ ) {
					var fns = arguments;
					return jQuery.Deferred(function( newDefer ) {
						jQuery.each( tuples, function( i, tuple ) {
							var action = tuple[ 0 ],
								fn = jQuery.isFunction( fns[ i ] ) && fns[ i ];
							// deferred[ done | fail | progress ] for forwarding actions to newDefer
							deferred[ tuple[1] ](function() {
								var returned = fn && fn.apply( this, arguments );
								if ( returned && jQuery.isFunction( returned.promise ) ) {
									returned.promise()
										.done( newDefer.resolve )
										.fail( newDefer.reject )
										.progress( newDefer.notify );
								} else {
									newDefer[ action + "With" ]( this === promise ? newDefer.promise() : this, fn ? [ returned ] : arguments );
								}
							});
						});
						fns = null;
					}).promise();
				},
				// Get a promise for this deferred
				// If obj is provided, the promise aspect is added to the object
				promise: function( obj ) {
					return obj != null ? jQuery.extend( obj, promise ) : promise;
				}
			},
			deferred = {};

		// Keep pipe for back-compat
		promise.pipe = promise.then;

		// Add list-specific methods
		jQuery.each( tuples, function( i, tuple ) {
			var list = tuple[ 2 ],
				stateString = tuple[ 3 ];

			// promise[ done | fail | progress ] = list.add
			promise[ tuple[1] ] = list.add;

			// Handle state
			if ( stateString ) {
				list.add(function() {
					// state = [ resolved | rejected ]
					state = stateString;

				// [ reject_list | resolve_list ].disable; progress_list.lock
				}, tuples[ i ^ 1 ][ 2 ].disable, tuples[ 2 ][ 2 ].lock );
			}

			// deferred[ resolve | reject | notify ]
			deferred[ tuple[0] ] = function() {
				deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
				return this;
			};
			deferred[ tuple[0] + "With" ] = list.fireWith;
		});

		// Make the deferred a promise
		promise.promise( deferred );

		// Call given func if any
		if ( func ) {
			func.call( deferred, deferred );
		}

		// All done!
		return deferred;
	},

	// Deferred helper
	when: function( subordinate /* , ..., subordinateN */ ) {
		var i = 0,
			resolveValues = core_slice.call( arguments ),
			length = resolveValues.length,

			// the count of uncompleted subordinates
			remaining = length !== 1 || ( subordinate && jQuery.isFunction( subordinate.promise ) ) ? length : 0,

			// the master Deferred. If resolveValues consist of only a single Deferred, just use that.
			deferred = remaining === 1 ? subordinate : jQuery.Deferred(),

			// Update function for both resolve and progress values
			updateFunc = function( i, contexts, values ) {
				return function( value ) {
					contexts[ i ] = this;
					values[ i ] = arguments.length > 1 ? core_slice.call( arguments ) : value;
					if( values === progressValues ) {
						deferred.notifyWith( contexts, values );
					} else if ( !( --remaining ) ) {
						deferred.resolveWith( contexts, values );
					}
				};
			},

			progressValues, progressContexts, resolveContexts;

		// add listeners to Deferred subordinates; treat others as resolved
		if ( length > 1 ) {
			progressValues = new Array( length );
			progressContexts = new Array( length );
			resolveContexts = new Array( length );
			for ( ; i < length; i++ ) {
				if ( resolveValues[ i ] && jQuery.isFunction( resolveValues[ i ].promise ) ) {
					resolveValues[ i ].promise()
						.done( updateFunc( i, resolveContexts, resolveValues ) )
						.fail( deferred.reject )
						.progress( updateFunc( i, progressContexts, progressValues ) );
				} else {
					--remaining;
				}
			}
		}

		// if we're not waiting on anything, resolve the master
		if ( !remaining ) {
			deferred.resolveWith( resolveContexts, resolveValues );
		}

		return deferred.promise();
	}
});
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip 【备注】 1、该资源内项目代码都经过测试运行成功,功能ok的情况下才上传的,请放心下载使用!有问题请及时沟通交流。 2、适用人群:计算机相关专业(如计科、信息安全、数据科学与大数据技术、人工智能、通信、物联网、自动化、电子信息等)在校学生、专业老师或者企业员工下载使用。 3、用途:项目具有较高的学习借鉴价值,不仅适用于小白学习入门进阶。也可作为毕设项目、课程设计、大作业、初期项目立项演示等。 4、如果基础还行,或热爱钻研,亦可在此项目代码基础上进行修改添加,实现其他不同功能。 欢迎下载!欢迎交流学习!不清楚的可以私信问我! 基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip基于Django+python编写开发的毕业生就业管理系统支持学生教师角色+db数据库(毕业设计新项目).zip
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值