jquery.Deferred promise解決非同步回調

來源:互聯網
上載者:User

標籤:

我們先來看一下編寫AJAX編碼經常遇到的幾個問題:

1.由於AJAX是非同步,所有依賴AJAX返回結果的代碼必需寫在AJAX回呼函數中。這就不可避免地形成了嵌套,ajax等非同步作業越多,嵌套層次就會越深,代碼可讀性就會越差。

$.ajax({      url: url,      data: dataObject,      success: function(){      console.log("I depend on ajax result.");      },      error: function(){}  });    console.log("I will print before ajax finished.");  

2.如果AJAX請求之間存在依賴關係,我們的代碼就會形成Pyramid of Doom(金字塔厄運)。比如我們要完成這樣一件事:有4個供Ajax訪問的url地址,需要先Ajax訪問第1個,在第1個訪問完成後,用拿到的返回資料作為參數再訪問第2個,第2個訪問完成後再第3個...以此到4個全部訪問完成。按照這樣的寫法,似乎會變成這樣:

$.ajax({      url: url1,      success: function(data){          $.ajax({              url: url2,              data: data,              success: function(data){                  $.ajax({                      //...                  });              }              });      }  });  

3.考慮這種情境,假如我們同時發送兩個Ajax請求,然後要在兩個請求都成功返回後再做一件接下來的事,想一想如果只按前面的方式在各自的調用位置去附加回調,這是不是很困難?

 

可以看到:JavaScript中類似於AJAX這種非同步操作,會導致代碼嵌套層次複雜,可讀性差,有的時候甚至是實現需求都非常困難。為瞭解決這種非同步回調難的問題,CommonJS組織制定了非同步模式編程規範Promises/A。目前該規範已經有了很多的實現者,比如Q, when.js, jQuery.Deffered()等。我們以jQuery.Deffered學習下Promise。

 

Promise的狀態

Promise對象有3種可能的狀態:肯定狀態(resolved)、否定狀態(rejected)、等待狀態(pending)。剛開始建立的Promise對象處於pending狀態,只能從pending變成resolved或者是從pending變成rejected狀態。

var df1 = $.Deferred();   console.log(df1.state());//pending    var df2 = $.Deferred();   df2.resolve();//resolved  console.log(df2.state());    var df3 = $.Deferred();   df3.reject();  console.log(df3.state());//rejected  

$.Deferred()建立一個延遲物件(也就是Promise對象),deferred.state()可以擷取Promise對象當前所處的狀態。deferred.resolve()和deferred.reject()則是用來改變Promise對象的狀態。

Promise添加回呼函數

Promise對象有3種狀態,我們可以分別為這3種狀態註冊回呼函數。當Promise處於某個狀態的時候,會觸發這個狀態下註冊的回呼函數。

 

var df = $.Deferred();   df.done(function(){alert("success");});  df.fail(function(){alert("fail");});  df.progress(function(){alert("progress");});    df.notify();    df.resolve();  // df.reject();  

done()、fail()、progress()分別註冊resolved、rejected、pending狀態下的回呼函數。通過resolve()、reject()、notify()可以觸發事先註冊的回呼函數。

Promise是支援鏈式調用的,上面的代碼可以寫成下面的樣子。

var df = $.Deferred();   df.done(function(){alert("success");})  .fail(function(){alert("fail");})  .progress(function(){alert("progress");});  

Promise支援多個回呼函數,會按照註冊順序調用。

var df = $.Deferred();   df.done(function(){alert("first");})  .fail(function(){alert("fail");});    df.done(function(){alert("second");});  df.done(function(){alert("third");});    df.resolve();  

deferred.always()添加的回呼函數,無論Promise是resolved狀態還是rejected狀態,都會被調用。

 
var df1 = $.Deferred();   df1.always(function(type){alert(type);});  df1.resolve("resolve");    var df2 = $.Deferred();   df2.always(function(type){alert(type);});  df2.reject("reject");  

progress()和notify()能夠用來實現進度條效果,因為notify()允許調用多次,而reject()和resolve()只能調用一次。這個很好理解,因為一旦狀態變成resolved或者是rejected,就不能再改變其狀態,也沒有必要。

var df = $.Deferred();     df.done(function(){alert("success");});    df.fail(function(){alert("fail");});    df.progress(function(){alert("progress");});        // resolve()調用2次,但是只能觸發1次success  df.resolve();    df.resolve();      var mudf = $.Deferred();     mudf.done(function(){alert("success");});    mudf.fail(function(){alert("fail");});    mudf.progress(function(){alert("progress");});        // 每次調用notify都會觸發progress回呼函數  mudf.notify("%10");    mudf.notify("%20");    

rejectWith()、resolveWith()、notifyWith()功能上和reject()、resolve()、notify()沒有什麼差別,主要差別在於回呼函數中的執行內容(方法中的this)和參數形式。具體差別可以參考"JQuery.Callbacks系列一:api使用

// 老的ajax寫法  $.ajax({    url: "test.html",    success: function(){      alert("success");    },    error:function(){      alert("error");    }  });    // 使用promise後的寫法  $.ajax("test.html")   .done(function(){})   .fail(function(){})   .done(function(){)   .fail(function(){);  

 

JQuery中的Deferred對象與Promise對象區別

JQuery.Deferred相關的API,有的返回的是Deferred對象,有的返回的是Promise對象。如done()、reject()等大部分函數返回的都是Deferred對象,$.when()和then()函數返回的是Promise對象。具體可以參考JQuery API文檔。

JQuery官方對Promise Objects的解釋是:

This object provides a subset of the methods of the Deferred object (then, done, fail, always, progress, state and promise) to prevent users from changing the state of the Deferred.

可以看到Promise對象其實就是Deferred對象的一部分,Deferred對象提供了notify、reject、resolve等改變狀態的方法,但是Promise對象沒有提供這些方法。

 

文章開始提到的AJAX問題1~3,問題1可以很容易通過Promise得到解決。問題2和問題3是通過$.when()和deferred.then()得到解決,由於這2個API相對來說複雜一些,以後的文章再分析這2個API。

 

詳解"這篇文章中的fire()和fireWith()。

 

上面簡單的介紹了Promise的使用方式,我們可以用Promise的方式來編寫AJAX代碼。可以很容易地看出:使用Promise後代碼嵌套層次少了,代碼是縱向增長的,而不再是橫向增長。而且使用Promise,可以指定多個ajax回呼函數。

   jquery Deferred 快速解決非同步回調的問題 
function ok(name){   var dfd = new $.Deferred();  callback:func(){      return dfd.resolve( response );  }   return dfd.promise();} $.when(ok(1),ok(2)).then(function(resp1,resp2){})

//相關API 分成3類

1類:$.when(pro1,pro1) 將多個 promise 對象以and的關係 合并為1個

2類:promise 激發為 解決 deferred.resolve([ args ] ) deferred.resolveWith( context, [ args ] )

和 拒絕 .reject  .rejectWith

context 上下文 替換 this 和通知 .notify  .notifyWith

3類: 對激發的響應  解決時deferred.done(args) 拒絕時 deferred.fail() 通知時 deferred.progress()

不管 解決 或 拒絕 deferred.always()


deferred.then( doneCallbacks, failCallbacks [, progressCallbacks] )


promise(或者叫deferred 延遲物件如何擷取?)

var dfd = new $.Deferred(); return dfd.promise();

 

返回promise目前狀態

deferred.state()  pending(尚未完成) resolved rejected

管道

 

deferred.pipe( [ doneFilter ], [ failFilter ] )   var defer = $.Deferred() var filtered = defer.pipe( null, function( value ) {    return value * 3;}); defer.reject( 6 );filtered.fail(function( value ) {   alert( "Value is ( 3*6 = ) 18: " + value );});

 

jquery.Deferred 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.