$.ajax()引發的對Deferred的總結

來源:互聯網
上載者:User

標籤: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的總結 (轉)

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.