jquery 源码分析之Deferred

  

一、Deferred对象

      Deferred对象就是jQuery的回调函数解决方案。Deferred的对象的含义就是延迟到未来某一个点再执行。它解决了如何处理耗时操作的问题,对那些操作提供了更好的控制

     ,以及统一的编程接口。

二、用法举例

var dfd= $.Deferred();

    dfd.done(function(){
        alert("Done");
    }).fail(function(){
        alert("failed")
    }).progress(function(){
        alert("progress");
    });
    dfd.notify();
    dfd.resolve();
    //dfd.reject();

三、改变了传统$.ajax的写法

传统的ajax请求是

$.ajax({
   url:"./test.txt",
    success:function(data){
          alert(data);
       },
    error:function(){
           alert("error");
        }
});


   $.ajax()操作完成之后,如果是低于1.5.0的版本的jQuery,返回的是XHR对象,你没法进行链式操作;如果高于1.5.0版本,返回的是Deferred的对象,可以进行链式操作。

$.ajax("./test.txt").done(function(data){
        alert(data);
    }).fail(function(){
        alert("failed")
    });

done相当于是success方法,fail相当于是error方法。

四、源码分析

 1.可以传入参数

$.extend({
    Deferred:function(func){
if ( func ) {
    func.call( deferred, deferred );
   }

// All done!
  return deferred;
  }
})
Deferred对象是扩展到了jquery对象上,是一个工具方法。可以传入参数。当传入参数时,该参数如果是函数就会立即执行。调用Deferred方法,最后返回一个deferred对象。

2.Deferred对象的几个方法和状态

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") ]
	],

Deferred有3种类型。事件添加有done 、fail和progress,这三个方法对应着Callbacks对象的add方法。事件触发有resolve、reject和notify,这三种方法对应着Callbacks对象的fire方法。done和resolve代表事件成功,fail和reject对应着事件执行失败,progress和notify对应着进行中。

 其中,resolve和reject只触发一次,因为jQuery.Callbacks("once memory"),而notify可以触发多次。事件成功和事件失败,有对应的状态resolved和rejected,事件进行中则没有状态。

那么这是如何对应的呢?

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

			// promise[ done | fail | progress ] = list.add
			promise[ tuple[1] ] = list.add;     //给promise对象添加done fail progress方法。

			// Handle state
			if ( stateString ) {          //如果有状态的话,进入if
				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 );     //i=0时,i^1=1,也就是说,如果执行了事件成功的done那么,后面的事件失败对应的Callbacks对象就会失效。同时,进度事件锁住,不会被触发。
			}

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

3.promise对象

    3.1 用法举例

  一般的Deferred对象有个问题,就是状态会被改变。

 var dfd= $.Deferred(),
        d,//
        wait=function(dfd){
            var task=function(){
                alert("Done");
                dfd.resolve();
            }
            setTimeout(task,500);
            return dfd;
        };
     d=wait(dfd);
     $.when(d)
        .done(function(){
            alert("Finished")
        })
        .fail(function(){
            alert("Failed");
        });
d.resolve();

在外部,改变了dfd对象的状态,那么回调的时候就不会再执行第二次的事件函数。

为了避免Deferred对象的状态被外部改变,jquery提供了deferred.promise()函数,该函数是promise对象的一个方法。

promise.promise( deferred );

promise: function( obj ) {
	return obj != null ? jQuery.extend( obj, promise ) : promise;
	}

当函数里面有参数时,会被promise对象属性和方法都扩展到入参,如果没有入参,直接返回promise对象本身。而promise对象本身没有resolve和reject方法。不能改变Deferred对象的状态。

 

var dfd= $.Deferred(),
        d,//
        wait=function(dfd){
            var task=function(){
                alert("Done");
                dfd.resolve();
            }
            setTimeout(task,500);
            return dfd.promise();
        };
 d=wait(dfd);
 $.when(d)
        .done(function(){
            alert("Finished")
        })
        .fail(function(){
            alert("Failed");
        });
 d.resolve();//报错

    3.2 源码解析

                   promise = {
				state: function() {
					return state;
				},
				always: function() { 
					deferred.done( arguments ).fail( arguments );//无论成功还是失败都会执行同一个函数
					return this;
				},
				then: function( /* fnDone, fnFail, fnProgress */ ) {//简写,里面的3个入参分别代表成功、失败和进行中要执行的函数
					var fns = arguments;
					return jQuery.Deferred(function( newDefer ) {<span style="white-space:pre">	</span>  //Deferred()里面的函数会议立即执行,传入的参数时deferred对象
						jQuery.each( tuples, function( i, tuple ) {
							var 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 {//对应Callbacks对象的fireWith方法
				  newDefer[ tuple[ 0 ] + "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 ) {  //有参数时,把promise对象扩展到入参对象上,没有返回promise对象
					return obj != null ? jQuery.extend( obj, promise ) : promise;
				}
			}




 





你可能感兴趣的:(jquery,jquery源码)