jq源码学习10_Deferred : 延迟对象 : 对异步的统一管理

基于jquery-2.0.3的源码学习

//10. Deferred : 延迟对象 : 对异步的统一管理
jQuery.extend({
  Deferred: function(func){
    // once表示回调函数列表只能被触发一次,memory表示会记录上一次触发回调函数列表时的参数,
    //触发后添加的任何回调函数都将用记录的参数值立即调用。
    //tuples 创建三个$.Callbacks对象,分别表示成功,失败,处理中三种状态
    var tuples =[
      [ "resolve", "done", jQuery.Callbacks("once memory"), "resolved" ],
			[ "reject", "fail", jQuery.Callbacks("once memory"), "rejected" ],
			[ "notify", "progress", jQuery.Callbacks("memory") ]
    ],
     // 初始状态。异步队列的初始状态为待定pending。
     //变量state在调用方法deferred.resolve()或deferred.resolveWidth()后被设置为字符串“resolved”,
     //表示成功状态,调用方法deferred.reject()或deferred.rejectWith()后被设置为字符串“rejected”,表示失败状态。
    state = "pending",
    //创建了一个promise对象,具有state、always、then、primise方法
    promise = {
      // deferred.state()用于返回异步队列的状态。
     // 如果方法deferred.state()返回“resolved”,意味着deferred.resolve()或者deferred.resolveWith()已经被调用,
     //成功回调函数已经执行或者正在执行;如果方法deferred.state()返回“rejected,
     //意味着deferred.reject()或者deferred.rejectWith()已经被调用,并且失败回调函数已经执行或者正在执行;
      state:function(){
        //确定一个Deferred对象的当前状态
        //deferred.state()方法返回一个字符串,代表Deferred对象的当前状态。 Deferred对象可以在三种状态之一:
       //pending: Deferred对象是尚未完成状态 (不是 "rejected" 或 "resolved").
      //resolved:  Deferred对象是在解决状态,这意味着,deferred.resolve() 或者 
      //deferred.resolveWith()被对象访问和doneCallbacks被访问(或在被调用的过程中) 。
     //rejected: Deferred对象是在被拒绝的状态,这意味着,deferred.reject() 或者 
     //deferred.rejectWith() 被对象访问和failCallbacks被访问(或在被调用的过程中) 。
         return state
      },
       // 在便捷方法always()中,采用链式语法依次调用方法done()、fail()重复添加回调函数,
       //并返回this以继续支持链式语法。调用方法done()、fail()时,关键字this始终指向当前异步队列,
       //因此实际上不借用方法apply()也可以用链式语法。
      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();
      },
      promise: function( obj ) {
        return obj != null ? jQuery.extend( obj, promise ) : promise;
      }
    },
    deferred = {};
    promise.pipe = promise.then;
    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;
    });
    promise.promise( deferred );

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

		// All done!
		return deferred;
  },
  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();
	}
});
//10. Deferred : 延迟对象 : 对异步的统一管理
发布了139 篇原创文章 · 获赞 27 · 访问量 24万+

猜你喜欢

转载自blog.csdn.net/chunchun1230/article/details/104197822