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({ url:"./test.txt", success:function(data){ alert(data); }, error:function(){ alert("error"); } });
$.ajax("./test.txt").done(function(data){ alert(data); }).fail(function(){ alert("failed") });
$.extend({ Deferred:function(func){ if ( func ) { func.call( deferred, deferred ); } // All done! return deferred; } })Deferred对象是扩展到了jquery对象上,是一个工具方法。可以传入参数。当传入参数时,该参数如果是函数就会立即执行。调用Deferred方法,最后返回一个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") ] ],
其中,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对象
一般的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();
为了避免Deferred对象的状态被外部改变,jquery提供了deferred.promise()函数,该函数是promise对象的一个方法。
promise.promise( deferred );
promise: function( obj ) { return obj != null ? jQuery.extend( obj, promise ) : promise; }
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();//报错
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; } }