標籤:time 答案 添加 程式 htm 告訴 strong button 方式
傳統的ajax寫法:
$.ajax({ url:"1.json", type:"get", success:function(data){}, error:function(){}});
jquery 1.7以後的新寫法,
$.ajax({ url:"1.json", type:"get" }).done(function(data){ }).fail(function(){ });
我就納悶了.$.ajax()返回的是XMLHttpRequest對象.
我們都知道XMLHttpRequest是ajax的一個核心對象,用於和伺服器互動的,
可是XMLHttpRequest對象根本就沒有什麼done,fail方法,
這裡的方法是怎麼加上去的呢?
我們從done入手.在官網api上搜尋done.
發現一個Deferred關鍵詞.
我們現在就從jQuery的Deferred開始講起吧.
Deferred對象是jqueryTeam Dev設計的,為了增強jquery的回調功能,在1.7版本中加入了jquery.
defer英語意思是延遲的意思.那麼他是如何延遲的呢?
首先來理解一下基本知識,要不然後面沒法說了.
$.Deferred([fun])
$.Deferred()沒有參數時 返回Deferred對象;
有參數時,表示在這個參數上做延遲或非同步作業,並且返回Deferred對象.
done(fn) 當延遲成功後調用該方法
fail(fn) 當延遲失敗時調用失敗
then(done,fail) 這個是done和fail的總寫方式
always(fn) 不管順延強制的成功還是失敗,都執行的方法
上面的fn可能是一個function,也有可能是多個以逗號分隔的function函數
resolve和reject方法一旦執行,表示開始執行done,fail,then,always方法,
注意Deferred對象可以一次掛接多個done,fail方法,按照你分布的順序依次執行.
resolve(value) 告訴對象執行done回調,value是參數
reject(value) 告訴對象執行fail回調,value是參數.
調用done回調代碼:
var dfd = $.Deferred();dfd.done(function(value) { alert(value);});dfd.resolve("執行done回調");
調用fail回調代碼:
var dfd = $.Deferred();dfd.done(function(value) { alert(value);});dfd.reject("執行fail回調");
調用then回調代碼:
var dfd = $.Deferred();var doneFun=function(value) { alert("done:"+value);};var failFun=function(value) { alert("fail:"+value);}dfd.then(doneFun,failFun);dfd.reject("思思博士");
調用always回調代碼:
var dfd = $.Deferred();var doneFun = function(value) { alert("done:" + value);};var failFun = function(value) { alert("fail:" + value);}dfd.then(doneFun, failFun).always(function() { alert("不管你延遲成功還是失敗,我都要執行always.");});dfd.resolve("我要執行done,但是這不影響我執行always!");
state() 返回deferred對象目前的狀態
1.pending:操作沒有完成
2.resolved:操作成功
3.rejected:操作失敗
代碼:
var dfd=$.Deferred();dfd.done(function(){ console.log("done");});console.log(dfd.state());dfd.resolve();console.log(dfd.state());
上面我們說了:resolve表示立馬執行回調,
所以這個地方的彈出是這樣的
var dfd=$.Deferred();dfd.progress(function(data){ alert(data);}).done(function(data){ alert("done:>>>>>"+data);}).fail(function(data){ alert("fail:>>>>"+data);});function getProcess(){ dfd.notify("我是progress回呼函數的參數"); var a=true; //下面判斷是為了執行done還是fail if(a){ dfd.resolve("執行done....."); }else{ dfd.reject("執行fail......"); }}
<input type="button" value="確定" onclick="getProcess()" />
根據以上分析,Deferred對象才有done這樣的反法,
根據$.ajax().done()推測$.ajax()返回的應該是Deferred對象?
姑且認為這個結論是對的吧.
那麼jQuey除了$.ajax()有done方法外,還有哪些東西有done方法.
$.when(d);d是一個或多個延遲物件,或者普通的JavaScript對象。
下面看一下參數是一個普通對象的.
現在說一說多個延遲的同一個調用
$.when($.ajax("1.json"), $.ajax("2.json"),$.ajax("3.json")).done(function(data1, data2,data3) { console.log(data1); console.log(data2); console.log(data3);}).fail(function(data1,data2,data3){ console.log(data1); console.log(data2); console.log(data3);});
他把$.ajax()對象給返回回來了
這個地方的用的是ajax做的延遲,
那麼我們能不能用setTimeout類比延遲
function delay(){ setTimeout(function(){ alert("執行啦"); },2000);} $.when(delay()).done(function(){ alert("done");});
不對,這個地方首先執行的是done,2s後執行的才是setTimeout.
思考思考,想一想上面的參數.
這個地方最多隻是將delay()當做參數傳遞給done回呼函數的參數.因為不是一個Deferred類型的參數.
因為$.ajax()返回Deferred類型才能使用done一樣.
那麼要怎麼樣才能讓delay返回一個Deferred對象來完成我們的延遲類比呢.
現在讓我們回想一下上面的第一串代碼$.Deferred();
這個可以返回Deferred類型.
改寫上面代碼:
var dfd=$.Deferred(); function delay(dfd){ var bool=true; setTimeout(function(){ alert("delay的setTimeout執行啦!"); if(bool){ dfd.resolve("done"); }else{ dfd.reject("fail"); } },2000); return dfd;}$.when(delay(dfd)).done(function(value){ alert(value);}).fail(function(value){ alert(value);});
這個時候我們終於實現了延遲,回到功能.
上面說了 done只要一遇到resolve或fail遇到reject就會立即執行,
那麼我們在底部添加一行代碼:
修改上面的代碼:
var dfd=$.Deferred(); function delay(dfd){ var bool=true; setTimeout(function(){ console.log("delay的setTimeout執行啦!"); if(bool){ dfd.resolve("done"); }else{ dfd.reject("fail"); } },2000); return dfd;}$.when(delay(dfd)).done(function(value){ console.log("done1"+value); }).fail(function(value){ console.log("fail1"+value);});dfd.resolve("我是來搗亂的....");
順序變成了這樣:
很明顯破壞了我們類比延遲的目的.
如何解決
將dfd從全域改成局部變數,這樣別人就不能輕易的改變狀態了.
function delay(){ var dfd=$.Deferred(); var bool=true; setTimeout(function(){ alert("delay的setTimeout執行啦!"); if(bool){ dfd.resolve("done"); }else{ dfd.reject("fail"); } },2000); return dfd;}$.when(delay()).done(function(value){ alert("done1"+value); }).fail(function(value){ alert("fail1"+value);});
還是那句話:done只要一遇到resolve或fail遇到reject就會立即執行
改寫上面的代碼:
function delay(){ var dfd=$.Deferred(); var bool=true; setTimeout(function(){ console.log("delay的setTimeout執行啦!"); if(bool){ dfd.resolve("done"); }else{ dfd.reject("fail"); } },2000); return dfd;}var delay2=delay();delay2.resolve();$.when(delay()).done(function(value){ console.log("done1"+value); }).fail(function(value){ console.log("fail1"+value);});
這個時候執行變成這樣,2s後:
如果我們的Deferred可以這樣任意的被篡改,那麼我們的程式健壯何在,
有沒有一個辦法讓外人無法訪問到Deferred對象,但是又不影響我們的回呼函數的調用.
答案是有:promise();
改寫代碼:
function delay(){ var dfd=$.Deferred(); var bool=true; setTimeout(function(){ console.log("delay的setTimeout執行啦!"); if(bool){ dfd.resolve("done"); }else{ dfd.reject("fail"); } },2000); return dfd.promise();}//var delay2=delay();//delay2.resolve();$.when(delay()).done(function(value){ console.log("done1"+value); }).fail(function(value){ console.log("fail1"+value);});
這個時候你在把注釋放開,就會報錯了.
在看下面這串代碼的報錯:
$.ajax().resolve();
是不是很熟悉的報錯.
所以我們的$.ajax()更確切的說最終返回的是Promise對象.
$.ajax(),$.when()說白了不過是一個方法而已.
既然jQuery能夠搞個$.ajax(),$.when()介面出來,我們理所當然的也能搞一個
這樣的介面出來了.
回到最上面的那串代碼:
$.Deferred(fn);
我們一直都是在用無參的$.Deferred();
那這個fn參數是幹嘛的呢?fn主要用來部署非同步或延遲操作的.
$.delay=$.Deferred(function(dfd){ setTimeout(function(){ alert("setTimeout執行啦!!!!"); dfd.resolve(); },2000);});$.delay.done(function(){ alert("done1");});
注意:這裡的dfd不需要我們調用時傳遞,自己會傳一個Deferred對象進去
這樣看上去是不是就和$.ajax()和$.when()差不多了.
但是又不太一樣,$.ajax()和$.when()可以傳參數我們的$.delay不能傳遞參數,他也不是一個方法,就是一個Promise對象.
繼續最佳化上面的代碼,使之可以傳遞參數:
$.delay = function(time) { return $.Deferred(function(dfd) { setTimeout(function() { alert("setTimeout執行啦!!!!"); dfd.resolve(); }, time); })}$.delay(5000).done(function() { alert("done1");});
代碼最佳化好了之後,功能實現了;
此時問題又來了.$.delay()是jQuery已經定義過的一個方法,我們定義的方法額jQuery重名了
不如我們吧$.delay()改成一個普通的方法,不更好.
var delay = function(time) { return $.Deferred(function(dfd) { setTimeout(function() { alert("setTimeout執行啦!!!!"); dfd.resolve(); }, time); })}delay(5000).done(function() { alert("done1");});
或者是這樣:
function delay(time) { return $.Deferred(function(dfd) { setTimeout(function() { alert("setTimeout執行啦!!!!"); dfd.resolve(); }, time); })}delay(5000).done(function() { alert("done1");});
上面說的是通過返回Promise對象使其有了done等介面,
能否直接在給出的函數上布置介面呢?這裡就用到了我們之前用到的promise()
代碼如下:
var dfd=$.Deferred();function delay(d,time) { setTimeout(function(){ alert("setTimeout執行啦!!"); d.resolve(); },time);}dfd.promise(delay);delay.done(function() { alert("done1");});delay(dfd,5000);
這裡又出現了dfd這樣的全域變數,而且在調用時還是需要傳遞dfd參數,似乎有點不好看,最佳化一下:
function ansy(time) { var dfd = $.Deferred(); function delay(d, time) { setTimeout(function() { alert("setTimeout執行啦!!"); d.resolve("我被done彈出來了"); }, time); } dfd.promise(delay); delay(dfd,time); return delay;}ansy(2000).done(function(value){ alert("done說:"+value);});
轉自:http://www.cnblogs.com/guoyansi19900907/p/5000267.html
$.ajax()引發的對Deferred的總結 (轉)