jquery.Deferred()

$().ready(function() {
			var cb = $.Callbacks();
			setTimeout(function() {
				alert(111)
				cb.fire();
			}, 2000);

			cb.add(function() {//这里先把函数存到数组里面,当定时器里面触发fire()方法的时候,就会触发数组里面这个函数的调用
				alert(222);
			});
		});
$().ready(function() {
			var cb = $.Deferred();
			setTimeout(function() {
				alert(111)
				cb.resolve();
			}, 2000);

			cb.done(function() {
				alert(222);
			});
		});


			setTimeout(function() {
				alert(111)
			}, 2000);

			alert(222);
//这种情况,会先弹出2后弹出1,因为定时器是异步的,如果想要先弹1后弹2,可以降alert放到定时器内,但是如果是函数的情况先,想要函数按照一定顺序执行,如果也放定时器内的话,这时候,作用域就发生了改变;其二是如果都忘定时器里面放的话,那么代码会很臃肿,一个定时器内的代码

这种情况如果使用延迟对象管理一下异步,就会

==

$.ajax('xxx.php').done(function(){ alert('成功'); }).fail(function(){ alert('失败'); });

      //上面这个ajax操作中,成功触发的是resolve,失败触发的是reject

      //那么jq当中是怎么样做到这种映射关系的呢?

下面的图片是deferred和promise对象的关系,

<!DOCTYPE HTML>
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>无标题文档</title>
<style>
	* {
    -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
    box-sizing: border-box;
    margin: 0;
    padding: 0;
	}
	body {
		font-size: 32px;
		background: #2C1C44;
		font-family: sans-serif;
		color: #FFF;
		font-family: "Playfair Display", serif;
		/*margin: 50px;*/
		margin: 0;
		overflow: hidden;
	}
</style>
<script src="jquery-2.0.3.js"></script>
</head>

<body>
	<script>
		$().ready(function() {
			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") ]
					],

					/*
					*数组中Callbacks中的参数once和Memory的作用是:
					看如下情况,如果是dfd.resolve()或dfd.reject(),那么成功/失败只会弹出一次,之后会弹的一直是111,原因是因为once,
					如果是dfd.notify(); 则不同,会一直循环弹出111、失败
					====情况1=====
						var dfd = $.Deferred();
						setInterval(function(){
							alert(111);
							//dfd.resolve();
							//dfd.reject();
							dfd.notify();
							
						},1000);
						dfd.done(function(){
							alert('成功');
						}).fail(function(){
							alert('失败');
						}).progress(function(){
							alert('进度中');
						});
					====/情况1=====
					====情况2=====
					*在Callbacks对象中,有memory的情况下,add的过程中就调用了fire()方法,例如:
						var cb = $.Callbacks('memory');
						cb.add(function(){
							alert(1);
						});
						
						cb.fire();
						
						$('input').click(function(){
							
							cb.add(function(){
								alert(2);
							});
							
						})
						上面的情况,弹出1的时候,不会弹出2,只有点击触发了input这个元素,才会弹出2,这里是add()添加函数进入数组的动作,但是因为有memory,所以就触发了fire()
					====/情况2=====
					====情况3======
					var dfd = $.Deferred();

					setTimeout(function(){
						
						alert(111);
						dfd.resolve();//执行这里的时候,状态已经触发
						
					},1000);
					
					dfd.done(function(){
						alert('aaa');
					});
					
					$('input').click(function(){
						
						dfd.done(function(){//点击的时候,done的的状态在之前已经触发了,所以这个done里面的操作会立即触发
							alert('bbb');
						});
						
					});
					这里的情况运用在于,第一次不触发,后面每次都会立即触发的业务情况中
					====/情况3=====
					*
					*
					*/
					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 ],//对应的就是Callbacks函数
						stateString = tuple[ 3 ];//这个是状态  如果是notify的话,那么stateString是否为undefined?

					// promise[ done | fail | progress ] = list.add
					promise[ tuple[1] ] = list.add;//回调对象的add方法,callbacks对象有个add方法,这里的add方法对应的就是Callbacks中的add方法,并且将和回调方法放到了promise对象下面
					/*
					*promise["done"]  promise["fail"]  promise["progress"] 这里做 映射,将Callbacks中的add方法映射到了primse上
					*/

					// 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对象下面
						deferred[ tuple[0] + "With" ]( this === deferred ? promise : this, arguments );
						return this;
					};
					deferred[ tuple[0] + "With" ] = list.fireWith;//这里将Callbacks的fire方法映射给differed
				});

				// Make the deferred a promise
				promise.promise( deferred );//promise.promise()==>这个方法将deferred对象作为参数传递进去,就是deferred继承了promise的所有的方法,并且,还比promise还多出三个状态方法

				// 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();
			}
			});

			//源码中,讲三个回调方法放到promise对象下面,而将三个状态方法放到了deferred对象下面,promise对象和deferred对象都是延迟对象,那么promise对象和deferred对象,他们俩的关系是什么和有什么区别呢?
			/*
			function aaa(){
				var dfd = $.Deferred()
				setTimeout(function(){
					dfd.resolve();
				},1000);
				return dfd;//这里的延迟对象是Deferred对象,因为这个对象下面有表示状态的方法,所以能改变状态,
			}
			var newDfd = aaa();
			newDfd.done(function(){
				alert('成功');
			}).fail(function(){
				alert('失败');
			});
			newDfd.reject();
			上面的情况,因为dfd.resolve();要延迟一秒后才能执行,而newDfd.reject();先执行,已经先把状态改成了reject的状态所以上面resolve的状态就不会再触发了。。。那么怎么样才能做到外面修改不了这个状态呢?
			只要将aaa函数中的return 改成return dfd.promise();就可以不让外部更改状态,return dfd.promise()这时候,调用Deferred对象的promise,因为没有传参数,所以,这个时候是promise对象,promise对象没有对应状态的方法,所以,外部改不了方法


			*/
		});
	</script>
</body>
</html>

猜你喜欢

转载自blog.csdn.net/rose999ying/article/details/86535293
今日推荐