jQuery 中的 Deferred 對象

參考鏈接

  1. jQuery API中文文檔
  2. jQuery.Deferred
  3. jQuery.when
  4. jQuery的deferred對象詳解
  5. jQuery deferred 對象的 promise 方法
  6. jQuery中的Deferred-詳解和使用

什麼是 deferred 對象?

延遲對象,在jQuery的1.5引入,是通過調用jQuery.Deferred()方法創建一個可鏈式調用的工具對象。 它可以註冊多個回調到回調隊列, 調用回調隊列,準備代替任何同步或異步函數的成功或失敗狀態。——jQuery API中文文檔

簡單說,deferred對象就是jQuery的回調函數解決方案。在英語中,defer的意思是"延遲",所以deferred對象的含義就是"延遲"到未來某個點再執行。它解決了如何處理耗時操作的問題,對那些操作提供了更好的控制,以及統一的編程接口。——阮一峯

deferred 對象的主要功能

  1. ajax 操作的鏈式寫法

   .done(function(){ alert("success"); })
   .fail(function(){ alert("error"); });


`$.ajax()` 操作完成後,如果使用的是低於1.5.0版本的jQuery,返回的是XHR對象,無法進行鏈式操作;如果是高於1.5.0版本,返回的是deferred對象,可以進行鏈式操作。可以看到,`done()` 相當於 `success` 方法,`fail()` 相當於 `error` 方法。採用鏈式寫法以後,代碼的可讀性大大提高。
  
這裏着重強調一下 **jqXHR 對象**,從 jQuery 1.5 開始, `$.ajax()` 返回的 **jqXHR對象** 本身就是 deferred 對象,因此可以像上面代碼中那樣進行鏈式調用。

> 從 jQuery 1.5 開始,$.ajax()返回的jqXHR對象 實現了 Promise 接口, 使它擁有了 Promise 的所有屬性,方法和行爲。(見Deferred object獲取更多信息)。爲了讓回調函數的名字統一,便於在$.ajax()中使用。jqXHR也提供.error() .success()和.complete()方法。這些方法都帶有一個參數,該參數是一個函數,此函數在 $.ajax()請求結束時被調用,並且這個函數接收的參數,與調用 $.ajax()函數時的參數是一致。這將允許你在一次請求時,對多個回調函數進行賦值,甚至允許你在請求已經完成後,對回調函數進行賦值(如果該請求已經完成,則回調函數會被立刻調用)。
  
**注意事項:** `jqXHR.success()`, `jqXHR.error()`, 和 `jqXHR.complete()` 回調從 jQuery 1.8開始 被棄用過時,從jQuery 3.0開始被刪除,你可以使用 `jqXHR.done()`, `jqXHR.fail()`, 和 `jqXHR.always()` 代替。

 2. **指定同一操作的多個回調函數**
deferred 對象的一大好處,就是它允許你自由添加多個回調函數。還是以上面的代碼爲例,如果ajax操作成功後,除了原來的回調函數,我還想再運行一個回調函數,怎麼辦?很簡單,直接把它加在後面就行了。

$.ajax("test.html")
   .done(function(){ alert('success'); })
   .fail(function(){ alert('error'); })
  .done(function(){ alert('第二個回調函數!'); });

回調函數可以添加任意多個,它們按照添加順序執行。

 3. **爲多個操作指定回調函數**
deferred 對象的另一大好處,就是它允許你爲多個事件指定一個回調函數,這是傳統寫法做不到的。

請看下面的代碼,它用到了一個新的方法 [jQuery.when()][3]:

$.when($.ajax("test1.html"), $.ajax("test2.html"))
   .done(function(){ alert('success'); })
   .fail(function(){ alert('error'); });

這段代碼的意思是,先執行兩個操作$.ajax("test1.html")和$.ajax("test2.html"),如果都成功了,就運行done()指定的回調函數;如果有一個失敗或都失敗了,就執行fail()指定的回調函數。

**$.when()** 方法的使用具體 [參見文檔][3]。

 4. **普通操作的回調函數接口**
deferred 對象的最大優點,就是它把這一套回調函數接口,從ajax操作擴展到了所有操作。也就是說,任何一個操作----不管是ajax操作還是本地操作,也不管是異步操作還是同步操作----都可以使用deferred對象的各種方法,指定回調函數。

我們來看一個具體的例子,爲一個很耗時的操作 wait 指定回調函數:

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('success'); })
  .fail(function () { alert('error'); });

另一種做法是直接將 wait 函數傳入 `$.Deferred()`:

$.Deferred(wait)
   .done(function(){ alert('success'); })
   .fail(function(){ alert('error'); });

jQuery 規定,`$.Deferred()` 可以接受一個**函數名**(注意,是函數名)作爲參數,`$.Deferred()` 所生成的 deferred 對象將作爲這個函數的默認參數。

更具體的信息請參見 [阮一峯的文檔][4]。

## deferred 對象的方法 ##
 1. `$.Deferred()` 生成一個 deferred 對象。
`jQuery.Deferred( [beforeStart ] )` 工廠函數創建一個新的deferred對象。
> 描述: 一個工廠函數,這個函數返回一個鏈式實用對象,用返回對象方法來在回調隊列中註冊多個回調, 調用回調隊列,傳遞任何同步或異步函數的成功或失敗狀態。

`beforeStart` : 類型 `Function( Deferred deferred )`,一個構造函數返回之前調用的函數。
> `jQuery.Deferred` 方法可以傳遞一個可選的函數, 這個函數在方法返回之前調用,**並且會把新的 deferred(延遲)對象作爲 this 對象,將其作爲第一個參數傳遞給函數**。例如,被調用的函數可以使用 `deferred.then()` 綁定回調。
 2. `deferred.done()` 指定操作成功時的回調函數。
 3. `deferred.fail()` 指定操作失敗時的回調函數。
 4. `deferred.promise()` 沒有參數時,返回一個新的 deferred。 對象,該對象的運行狀態無法被改變;接受參數時,作用爲在參數對象上部署 deferred 接口。
 5. `deferred.resolve()` 手動改變 deferred 對象的運行狀態爲"已完成",從而立即觸發 `done()` 方法。
> 一個 Deferred(延遲)對象開始於 pending 狀態。 任何回調使用 `deferred.then()`, `deferred.always()`, `deferred.done()`, 或者 `deferred.fail()` 添加到這個對象都是排隊等待執行。調用 `deferred.resolve()` 轉換 Deferred(遞延)到 resolved(解決)的狀態,並立即執行設置中任何的 doneCallbacks。調用 `deferred.reject()` 轉換 Deferred(遞延)到 rejected(拒絕)的狀態,並立即執行設置中任何的 failCallbacks。一旦對象已經進入瞭解決或拒絕狀態,它處於該狀態。回調仍然可以添加到解決或拒絕 Deferred(遞延)- 他們會立即執行。

`$.ajax()` 返回的 **jqXHR 對象** 會根據請求返回的結果,自動改變自身的執行狀態。但是,對於其他通過 `$.Deferred()` 方法生成的 deferred 對象,它們的執行狀態必須由程序員手動指定,由代碼決定在什麼時候觸發回調函數。
 6. `deferred.reject()` 這個方法與 `deferred.resolve()` 正好相反,調用後將 deferred 對象的運行狀態變爲"已失敗",從而立即觸發 `fail()` 方法。
 7. `$.when()` 爲多個操作指定回調函數。
 8. `deferred.then()` 方法
有時爲了省事,可以把 `done()` 和 `fail()` 合在一起寫,這就是 `then()` 方法。

$.when($.ajax( '/main.php' ))
   .then(successFunc, failureFunc);

如果 `then()` 有兩個參數,那麼第一個參數是 `done()` 方法的回調函數,第二個參數是 `fail()` 方法的回調方法。如果 `then()` 只有一個參數,那麼等同於 `done()`。
 9. `deferred.always()` 方法
這個方法也是用來指定回調函數的,它的作用是,不管調用的是 `deferred.resolve()` 還是 `deferred.reject()`,最後總是執行。
  

$.ajax( 'test.html' )

  .always( function() { alert('已執行!');} );
更多信息請參見 [jQuery API中文文檔][1]。


[1]: http://www.css88.com/jqapi-1.9/category/deferred-object/
[2]: http://www.css88.com/jqapi-1.9/jQuery.Deferred/
[3]: http://www.css88.com/jqapi-1.9/jQuery.when/
[4]: http://www.ruanyifeng.com/blog/2011/08/a_detailed_explanation_of_jquery_deferred_object.html
[5]: http://blog.allenm.me/2012/01/jquery_deferred_promise_method/
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章