jQuery deferred学习笔记
简介
在jQuery1.5.0版本引入,为了实现Deferred对象,jQuery改写了ajax。是由jQuery.Deferred()方法创建的链式对象。
$.Deferred在jQuery代码自身四处被使用(promise、DOM
ready、Ajax、Animation)
特性:使用Deferred对象可以添加多个回调函数; 延迟特性,处理耗时操作问题
- register multiple callbacks into callback queues
- invoke callback queues
- relay the success or failure state of any synchronous or asynchronous function
主要源码
jQuery1.9.1源码如下:
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() { ..... }, always: function() { .... }, then: function( /* fnDone, fnFail, fnProgress */ ) { .... }, // Get a promise for this deferred // If obj is provided, the promise aspect is added to the object promise: function( obj ) { ..... } }, deferred = {}; // Keep pipe for back-compat promise.pipe = promise.then; // Add list-specific methods jQuery.each( tuples, function( i, tuple ) { ... 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 */ ) { .... return deferred.promise(); } });
Callbacks 是jQuery的回调对象,用于添加回调、删除回调、执行回调等
jQuery.Callbacks = function( options ) {// Actual Callbacks object self = { // Add a callback or a collection of callbacks to the list add: function() { ... }, // Remove a callback from the list remove: function() { .... },
....
// Call all the callbacks with the given arguments fire: function() { self.fireWith( this, arguments ); return this; }, // To know if the callbacks have already been called at least once fired: function() { return !!fired; } }; return self; };
methods
jQuery下两个方法:
$.Deffered() ——创建Deffered对象,var deferred = $.Deffered(); $.when()——为多个操作指定回调函数
Deffered对象包含如下方法:
deferred.always()——执行回调函数,不管deffered 对象是 状态resolved或者是rejected (即不管成功或者失败,对应ajax中complete)(关于执行状态看下一章节) deferred.done()——当Deferred对象状态为resolved时执行回调函数 deferred.fail()——当Deferred对象状态为rejected时执行回调函数 deferred.then()——执行回调函数,deferred 对象是 状态resolved或者是rejected 或者是 in progress
deferred.isRejected()——判断状态是否为rejected
deferred.isResolved()——判断状态是否为resolved
deffered.state()——判断当前状态
deferred.promise()——返回Deferred的promise对象 deferred.reject()——reject a deferred对象,即将状态转为rejected( with the given args.) deferred.rejectWith()——与上面reject的区别:with the given context and args. 下面类似 deferred.resolve()——即将状态转为resolve deferred.resolveWith()——
deferred.notify()——call the progressCallbacks
deferred.notifyWith()——
deferred.pipe()——过滤参数
一般done/resolve fail/reject progress/notify 对应使用
执行状态
Deffered对象三种执行状态: resolved(已完成)、未完成、rejected(失败)
1. 如果执行状态是resovled,Deffered对象会立刻调用done()方法指定的回调函数
2. 如果执行状态是rejected,Deffered对象会立刻调用fail()方法指定的回调函数
3. 如果执行状态是未完成,Deffered对象会继续等待或者是调用progress()方法指定的回调函数
ajax及简单链式操作
eg:
ajax方式:
$.ajax("test.jsp").success(function(result){alert("success! data is :"+result);}) .error(function(){alert("Error")}) .complete(function(){alert("complete!")}); 或者: $.ajax({ url:"test.jsp", success:function(result){alert("success! data is :"+result);}, error: function(){alert("Error!");}, complete:function(){alert("complete!")},
});
使用Deferred:
由于$.ajax 方法和$.get方法返回的是jqXHR对象(源自Deferred对象)因而上面的操作可以以下面的方式实现。
$.ajax("test.jsp").done(function(result){alert("success! data is :"+result);}) .fail(function(){alert("Error")}) .always(function(){alert("finished");});
注意:$.ajax()中jqXHR.success(), jqXHR.error(), jqXHR.complete(), 在jquery 1.8中已经弃用,应该使用done(),fail()和always()
done/resolve fail/reject progress/notify
done/resolve
var dfd = $.Deferred(); dfd.done(function(){ console.log("###############") }); $("button").on("click",function(){ dfd.resolve(); });
点击按钮,输出 ###############
fail/reject
var dfd = $.Deferred(); dfd.fail(function(){ console.log("###############") }); $("button").on("click",function(){ dfd.reject(); });
点击按钮,输出 ###############
progress/notify
eg1:
var dfd = $.Deferred(); dfd.progress(function(){ console.log("###############") }); $("button").on("click",function(){ dfd.notify(); });
点击按钮,输出 ###############
eg2:使用notify间隔的执行回调函数
var dfd = $.Deferred(); dfd.progress(function(){ console.log("###############"); }); $("button").on("click",function(){ setInterval(function(){ dfd.notify(); },1000); });
点击按钮,每1s输出一次##################
执行多个回调函数
eg1:
$.ajax("test.jsp").done(function(){console.log("the first callback");}) .done(function(){console.log("the second callback");}) .done(function(){console.log("the third callback");}) .fail(function(){console.log("Error")}); 或者: $.ajax("test.jsp").success(function(){console.log("the first callback");}) .success(function(){console.log("the second callback");}) .success(function(){console.log("the third callback");}) .error(function(){console.log("Error")});
输出:
the first callback
the second callback
the third callback
eg2:
deferred对象的done方法定义如下:deferred.done( doneCallbacks [, doneCallbacks ] ) 可以传入 array of functions
success也可达到相同效果,但是已弃用不建议使用
$.ajax("test.jsp").done([f1,f2,f3],[f2,f3]) .done(function(){console.log("the fourth callback");}) .fail(function(){alert("Error")}); function f1(){ console.log("the first callback"); } function f2(){ console.log("the second callback"); } function f3(){ console.log("the third callback"); }
输出结果如下:
the first callback
the second callback
the third callback
the second callback
the third callback
the fourth callback
eg3: 使用jQuery.Deferred()创建Deferred对象
简单使用done方法和resolve方法
function f1(){ console.log("the first callback"); } function f2(){ console.log("the second callback"); } function f3(){ console.log("the third callback"); } var dfd = $.Deferred(); dfd.done([f1,f2,f3],[f2,f3]) .done(function(){console.log("finished");}); $("button").on("click",function(){ dfd.resolve(); });
点击button,输出:
the first callback
the second callback
the third callback
the second callback
the third callback
finished
eg4. 给resolve添加args
function f1(arg){ console.log(arg+"the first callback"); } function f2(arg){ console.log(arg+"the second callback"); } function f3(arg){ console.log(arg+"the third callback"); } var dfd = $.Deferred(); dfd.done([f1,f2,f3],[f2,f3]) .done(function(){console.log("finished");}) .always(function(arg){console.log(arg+"end");}); $("button").on("click",function(){ dfd.resolve("###############"); });
输出如下:
###############the first callback
###############the second callback
###############the third callback
###############the second callback
###############the third callback
finished
###############end
then和pipe
pipe
使用pipe可以过滤参数,但是jQuery 1.8后已经启用pipe方法,建议使用then
pipe方法定义为:deferred.pipe( [doneFilter ] [, failFilter ] [, progressFilter ] ) returns a new promise
eg1:一次性定义done fail 和progress
function f1() { console.log(‘done‘); } function f2() { console.log(‘fail‘); } function f3() { console.log(‘progress‘); } var deferred = $.Deferred(); deferred.pipe(f1, f2, f3); $("button").on("click",function(){ deferred.reject(); });
点击按钮,输出 fail, 可以根据需要修改deferred.reject 为resolve或者是notify
eg2:
var dfd = $.Deferred(); dfd.pipe(function(arg){return "(*^__^*)"+arg;}); dfd.done(function(arg){ console.log(arg) }); $("button").on("click",function(){ dfd.resolve("###############"); });
点击按钮输出:
(*^__^*)###############
eg3:
var dfd = $.Deferred(); argFilter = dfd.pipe(null, function(arg){return "(*^__^*)"+arg;}); argFilter.fail(function(arg){ console.log(arg) }); $("button").on("click",function(){ dfd.reject("###############"); });
输出结果同上
then
deferred.then( [doneFilter ] [, failFilter ] [, progressFilter ] )
function f1() { console.log(‘done‘); } function f2() { console.log(‘fail‘); } function f3() { console.log(‘progress‘); } var deferred = $.Deferred(); deferred.then(f1, f2, f3); $("button").on("click",function(){ deferred.reject(); });
效果同pipe
when为多个操作指定回调函数
jQuery.when(deferreds);
如果传入单个deferred, 返回promise对象,后面可以链式添加then等方法
如果传入多个deferred,返回a new master deferred对象,该对象集合所有deferred对象的状态,如果所有deferred对象是resollve则结果是resolve,如果有一个是reject则结果是reject
eg1:
$.when($.ajax("test.jsp")).done(function(){console.log("done");});
结果:
GET http://localhost:8080/javascript/jQuery/test.jsp 200 OK 83ms done
eg2:
function f1() { console.log(‘done‘); } function f2() { console.log(‘fail‘); } function f3() { console.log(‘progress‘); } $.when($.ajax("test.jsp")).then(f1,f2,f3);
结果同上
eg3:
$.when($.ajax("test.jsp"),$.ajax("demo.jsp")).done(function(){console.log("done");});
结果:
GET http://localhost:8080/javascript/jQuery/test.jsp 200 OK 83ms GET http://localhost:8080/javascript/jQuery/demo.jsp 200 OK 460ms done
eg4:
<style> div { height: 50px; width: 50px; float: left; margin-right: 10px; display: none; background-color: #090; } </style> <button>button</button> <div></div> <div></div> <div></div> <div></div>
var effect = function() { return $( "div" ).fadeIn( 800 ).delay( 1200 ).fadeOut(); }; $( "button" ).on( "click", function() { $.when( effect() ).done(function() { console.log("finished"); }); });
effect()方法执行完后输出 finished;
.promise()
.promise([type][,target]) return a promise object 当所有与其相关的action结束后变为resolve状态
(The .promise()
method returns a
dynamically generated Promise that is resolved once all actions of a certain
type bound to the collection, queued or not, have ended.)
eg1:
var button = $( "<button>" ); button.promise().done(function( arg ) { console.log( this === button && arg === button ); //true });
eg2:
<style> div { height: 50px; width: 50px; float: left; margin-right: 10px; display: none; background-color: #090; } </style> <button>button</button> <div></div> <div></div> <div></div> <div></div>
$( "button" ).on( "click", function() { $( "div" ).each(function( i ) { $( this ).fadeIn().fadeOut( 1000 * ( i + 1 ) ); }); $( "div" ).promise().done(function() { console.log("finished"); }); });
animation结束后输出finished,效果等价于when 中的eg4
相关: http://api.jquery.com/category/deferred-object/
http://www.cnblogs.com/littledu/articles/2811728.html
http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
郑重声明:本站内容如果来自互联网及其他传播媒体,其版权均属原媒体及文章作者所有。转载目的在于传递更多信息及用于网络分享,并不代表本站赞同其观点和对其真实性负责,也不构成任何其他建议。