認識jQuery的Promise

先前瞭解了ES6的Promise對象,來看看jQuery中的Promise,也就是jQuery的Deferred對象。jquery

打開瀏覽器的控制檯先。ajax

<script>
    var defer = $.Deferred();
    console.log(defer);
</script>

數組

運行結果:promise

和ES6的Promise對象長的有點像,jQuery的Deferred對象也有resolve、reject、then方法,還有done、fail、always......方法。jQuery就是用這個Deferred對象來註冊異步操做的回調函數,修改並傳遞異步操做的狀態。瀏覽器

玩玩Deferred:dom

<script>
    function runAsync(){
        var defer = $.Deferred();
        //作一些異步操做
        setTimeout(function(){
            console.log('執行完成');
            defer.resolve('異步請求成功以後返回的數據');
        }, 1000);
        return defer;
    }
    runAsync().then(function(data){
        console.log(data)
    });
</script>

異步

 運行以後,Deferred對象的實例defer經過resolve方法把參數 「異步請求成功以後返回的數據」 傳回到then方法中進行接收,,打印。函數

和ES6的Promise類似,可是有一點點區別,再看下Promise:spa

<script>
    function runAsync(){
        var p = new Promise(function(resolve, reject){
           
            setTimeout(function(){
                console.log('執行完成');
                resolve('異步請求成功以後返回的數據');
            }, 1000);
        });
        return p;            
    }

    runAsync().then(function(data){
        console.log(data);
    });
</script>

code

咱們發現:

一、建立Deferred對象的時候沒有傳參;而建立Promise對象的時候,傳了參數(傳了一個匿名函數,函數也有兩個參數:resolve、reject);

二、Deferred對象直接調用了resolve方法;而Promise對象則是在內部調用的resolve方法;

說明:Deferred對象自己就有resolve方法,而Promise對象是在構造器中經過執行resolve方法,給Promise對象賦上了執行結果的狀態。

這樣就有一個弊端:由於Deferred對象自帶resolve方法,拿到Deferred對象以後,就能夠隨時調用resolve方法,其狀態能夠進行手動干預了

<script>
    function runAsync(){
        var defer = $.Deferred();
        //作一些異步操做
        setTimeout(function(){
            console.log('執行完成');
            defer.resolve('異步請求成功以後返回的數據');
        }, 1000);
        return defer;
    }
  
var der = runAsync();
   der.then(function(data){
        console.log(data)
   });
   der.resolve('在外部結束'); 
</script>

 這樣的話就直接在外部直接給Deferred設置了狀態,打印「在外部結束」,1s後打印「執行完成」,不會打印「異步請求成功以後返回的數據」了。

顯然,這很差。我發個異步請求,還沒收到數據就讓人在外部給我結束了。。。。。。。

固然這個坑jQuery確定會填的,在Deferred對象上有一個promise方法,是一個受限的Deferred對象

<script>
    function runAsync(){
        var def = $.Deferred();
        //作一些異步操做
        setTimeout(function(){
            console.log('執行完成');
            def.resolve('請求成功以後返回的數據');
        }, 2000);
        return def.promise(); //就在這裏調用
    }
</script>

所謂受限的Deferred對象,就是沒有resolve和reject方法的Deferred對象。這樣就沒法在外邊改變Deferred對象的狀態了。

Deferred對象的then方法和done、fail語法糖

咱們知道,在ES6的Promise規範中,then方法接受兩個參數,分別是執行完成和執行失敗的回調,而jquery中進行了加強,還能夠接受第三個參數,就是在pending狀態時的回調,以下:

deferred.then( doneFilter [, failFilter ] [, progressFilter ] )

then方法

<script>
    function runAsync(){
        var def = $.Deferred();
        //作一些異步操做
        setTimeout(function(){
              var num = Math.ceil(Math.random()*10); //生成1-10的隨機數
               if(num<=5){
                   def.resolve(num);
               }
               else{
                   def.reject('數字太大了');
               }
        }, 2000);
        return def.promise(); //就在這裏調用
    }

    runAsync().then(function(d){
        console.log("resolve");
        console.log(d);
    },function(d){
        console.log("reject");
        console.log(d);
    })

</script>

Deferred對象的then方法也是能夠進行鏈式操做的。

done,fail語法糖,分別用來指定執行完成和執行失敗的回調,與這段代碼是等價的:

<script>
    function runAsync(){
        var def = $.Deferred();
        //作一些異步操做
        setTimeout(function(){
              var num = Math.ceil(Math.random()*10); //生成1-10的隨機數
               if(num<=5){
                   def.resolve(num);
               }
               else{
                   def.reject('數字太大了');
               }
        }, 2000);
        return def.promise(); //就在這裏調用
    }

    runAsync().done(function(d){
        console.log("resolve");
        console.log(d);
    }).fail(function(d){
        console.log("reject");
        console.log(d);
    })

</script>

always的用法

jquery的Deferred對象上還有一個always方法,不論執行完成仍是執行失敗,always都會執行,有點相似ajax中的complete。

$.when的用法

jquery中,還有一個$.when方法來實現Promise,與ES6中的all方法功能同樣,並行執行異步操做,在全部的異步操做執行完後才執行回調函數。不過$.when並無定義在$.Deferred中,看名字就知道,$.when,它是一個單獨的方法。與ES6的all的參數稍有區別,它接受的並非數組,而是多個Deferred對象,以下:

<script>
 function runAsync(){
        var def = $.Deferred();
        //作一些異步操做
        setTimeout(function(){
              var num = Math.ceil(Math.random()*10); //生成1-10的隨機數
              def.resolve(num);   
        }, 2000);
        return def.promise(); //就在這裏調用
    }
    $.when(runAsync(), runAsync(), runAsync()) .then(function(data1, data2, data3){
     console.log(
'所有執行完成');
     console.log(data1, data2, data3);
  });
</script>

jquery中沒有像ES6中的race方法嗎?就是以跑的快的爲準的那個方法。對的,jquery中沒有。
以上就是jquery中Deferred對象的經常使用方法了。
 
在上一篇和本篇當中,都是用一次性定時器來代替了異步請求進行數據處理。爲何沒用ajax呢,不是由於麻煩,在這裏要說一下ajax和Deferred的聯繫:
jquery的ajax返回一個受限的Deferred對象,也就是沒有resolve方法和reject方法,不能從外部改變狀態,既然是Deferred對象,那麼咱們上面講到的全部特性,ajax也都是能夠用的。好比鏈式調用,連續發送多個請求:
<script>
req1 = function(){
    return $.ajax(/* **** */);
}
req2 = function(){
    return $.ajax(/* **** */);
}
req3 = function(){ 
  return $.ajax(/* **** */);
}
req1().then(req2).then(req3).done(function(){ console.log('請求發送完畢'); });
</script>

success、error與complete

這三個方法是咱們經常使用的ajax語法糖。

$.ajax(/*...*/)
.success(function(){/*...*/})
.error(function(){/*...*/})
.complete(function(){/*...*/})

有時候比較喜歡在內部做爲屬性來處理。

分別表示ajax請求成功、失敗、結束的回調。這三個方法與Deferred又是什麼關係呢?其實就是語法糖,success對應done,error對應fail,complete對應always,就這樣,只是爲了與ajax的參數名字上保持一致而已。

總結:

$.Deferred實現了Promise規範,then、done、fail、always是Deferred對象的方法。$.when是一個全局的方法,用來並行運行多個異步任務,與ES6的all是一個功能。ajax返回一個受限的Deferred對象,success、error、complete是ajax提供的語法糖,功能與Deferred對象的done、fail、always一致。

相關文章
相關標籤/搜索