前端編程提高之旅(九)----延遲物件,之旅----

來源:互聯網
上載者:User

前端編程提高之旅(九)----延遲物件,之旅----

            近日做內部推薦項目,在進入項目首頁時,需要進行預調用介面判斷,按照以往的習慣,應該將調用介面後執行的代碼,放入ajax請求success內執行。這樣當然可以,但是程式碼群組織和可讀性都沒有那麼高。通過查看Jquery官網api發現了deferred object(延遲物件)這個概念。

   一、API文檔的翻譯:

   延遲物件,在jquery1.5被引入,是調用jQuery.Deferred()方法產生的一個鏈式功用對象。它可以註冊多個回調到回調隊列,提取回調隊列,傳遞任何非同步或同步函數的成功或失敗狀態。
   延遲物件是一個鏈式的,類似於jquery對象的鏈式,但是它有自己的方法。在建立之後,你可以用任何下面涉及到的方法,無論是直接鏈式調用,還是儲存這個對象到變數,並在這個變數上調用一個或多個方法。

  • deferred.always()
    添加操作方法,不管延遲物件是處於解決狀態還是拒絕狀態都被調用。
  • deferred.done()
   添加操作方法,只有延遲物件處於已解決狀態才被調用
  • deferred.fail()
   添加操作方法,只有延遲物件處於被拒絕狀態才會被調用
  • deferred.isRejected()
    判斷一個延遲物件是否處於被拒絕狀態
  • deferred.isResolved()
    判斷一個延遲物件是否處於已解決狀態。
  • deferred.notify()
    調用一個給定變數的延遲物件上的進行中的回調。
  • deferred.notifyWith()
    調用一個給定變數和內容相關的延遲物件上的進行中的回調。
  • deferred.pipe()
    用來過濾and或or鏈式延遲的效用方法
  • deferred.progress()
    當延遲物件產生進行中通知時,添加操作被調用。
  • deferred.promise()
    返回延遲允諾對象。
  • deferred.reject()
    拒絕一個延遲物件並且調用任何給定參數的失敗回調。
  • deferred.rejectWith()
    拒絕回調對象,調用任何給定上下文和參數的失敗回調。
  • deferred.resolve()
    解決一個延遲物件,並且調用任何給定參數的完成回調。
  • deferred.resolveWith()
    解決一個延遲物件,並且調用任何給定上下文和參數的完成回調。
  • deferred.state()
    判斷當前延遲物件狀態。
  • deferred.then()
   當延遲物件被解決、拒絕或進行中添加方法被調用。
  • jQuery.Deferred()
    延遲物件的建構函式。
  • jQuery.when()
    提供一個方法執行基於一個或多個對象的回呼函數,回呼函數經常是代表非同步事件的延遲物件
  • .promise()
    當所有的綁定到集合、隊列或沒有的動作被完成返回一個promise對象。

   二、延遲物件分析與使用:

   不難得出結論,以上API包括了延遲物件的構建、延遲狀態設定方法、延遲狀態監聽方法。


延遲物件的資料結構

    延遲物件包括三種狀態:resolved(已解決)、rejected(未解決)、progress(進行中)。這三種狀態可以用延遲物件state方法即時查看。


延遲物件狀態查看

   延遲物件是jquery的回呼函數解決方案,延遲顧名思義就是延遲到未來某個點再執行,類似jquery 動畫函數中delay方法,區別在於後者是延遲固定時間,延遲物件則是通過固定狀態判斷順延強制的時機。

var dtd = $.Deferred(); // 建立一個deferred對象  var wait = function(dtd){    var tasks = function(){      alert("執行完畢!");      dtd.resolve(); // 改變deferred對象的執行狀態    };    setTimeout(tasks,5000);    return dtd;  };$.when(wait(dtd))  .done(function(){ alert("哈哈,成功了!"); })  .fail(function(){ alert("出錯啦!"); });

   上述代碼執行流程圖:



   上述代碼例子,延遲物件定義為一個全域對象,這樣就會造成延遲狀態,可以在任何時間變更。

   改進的方法一:

var dtd = $.Deferred(); // 建立一個Deferred對象  var wait = function(dtd){    var tasks = function(){      alert("執行完畢!");      dtd.resolve(); // 改變Deferred對象的執行狀態    };    setTimeout(tasks,5000);    return dtd.promise(); // 返回promise對象,promise對象只開放與狀態無關的方法,即那三種狀態方法不開放,無法設定  };  var d = wait(dtd); // 建立一個d對象,改為對這個對象進行操作  $.when(d)  .done(function(){ alert("哈哈,成功了!"); })  .fail(function(){ alert("出錯啦!"); });  d.resolve(); // 此時,這個語句是無效的

     上述代碼,在wait函數返回值是一個promise對象,由promise對象資料結構不難發現,promise對象擁有除了修改狀態方法以外延遲物件的所有方法,也就是說,promise對象無法改變執行狀態,這樣就能夠防止外界對狀態的更改。promise對象的資料結構


   改進方法二:

   將延遲物件構建成函數內部的局部變數,這樣更好的實現了封裝,防止外部對狀態進行改變。

var wait = function(dtd){    var dtd = $.Deferred(); //在函數內部,建立一個Deferred對象    var tasks = function(){      alert("執行完畢!");      dtd.resolve(); // 改變Deferred對象的執行狀態    };    setTimeout(tasks,5000);    return dtd.promise(); // 返回promise對象  };  $.when(wait())  .done(function(){ alert("哈哈,成功了!"); })  .fail(function(){ alert("出錯啦!"); });

       改進方法三:

  直接將函數名作為$.Deferred()參數傳入,$.Deferred()所產生的延遲物件會作為wait函數參數傳入函數。

var wait = function(dtd){    var tasks = function(){      alert("執行完畢!");      dtd.resolve(); // 改變Deferred對象的執行狀態    };    setTimeout(tasks,5000);    return dtd.promise(); // 返回promise對象  }; $.Deferred(wait)  .done(function(){ alert("哈哈,成功了!"); })  .fail(function(){ alert("出錯啦!"); });

$.Deferred()方式執行狀態


   三、項目使用方式:

   樂帝在內推項目中使用的是第二種方法,即將延遲物件作為局部變數定義,並返回promise對象。這裡promise對象與延遲物件除了不能改變狀態,對延遲狀態的記錄及監聽方法都相同。

 function loadInternalHost() {            var dtd = $.Deferred();               dtd.resolve();            return dtd.promise();//在原defferred對象上返回另一個deferred對象,兩個對象都會記錄最初deferred對象狀態,但後者不能改變狀態,其他方法一致        }



promise對延遲狀態的記錄

    當分別調用兩個介面時,延遲監聽函數允許為多個事件指定一個回調。

    如下代碼,分別取得內推城市及內推公告兩部分資料後,執行後續載入資料的動作。

$.when(getInternalRecommendCitys(), getComment()).done(function () {                getInternalRecommendJobAdList(oldSearchData.keyWord, oldSearchData.locId);            });function getInternalRecommendCitys() {            var dtd = $.Deferred();            $.ajax({                type: "get",                data: {                    "openId": openId                },                dataType: "json",                url: "../api/InternalInfo/InternalRecommendCitys",                success: function (data) {                    $city = $("#citySelect");                    for (var i = 1; i < data.length; i++) {                        $str = $("<option></option>");                        $str.text(data[i].name);                        $str.val(data[i].value);                        $city.append($str);                        dtd.resolve();                    }//將可選城市匯入到挑選清單                },                error: function () {                    dtd.resolve();                }            });            return dtd.promise();        }        function getComment() {            var dtd = $.Deferred();            $.ajax({                type: "get",                data: {                    "openId": openId                },                dataType: "json",                url: "../api/InternalInfo/GetComment",                success: function (data) {                    $(".notice-content pre").html(data.data);                    dtd.resolve();                },                error: function () {                    dtd.resolve();                }            });//擷取公告資料            return dtd.promise();        }


聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.