選單
GSS 技術部落格
在這個園地裡我們將從技術、專案管理、客戶對談面和大家分享我們多年的經驗,希望大家不管是喜歡或是有意見,都可以回饋給我們,讓我們有機會和大家對話並一起成長!
若有任何問題請來信:gss_crm@gss.com.tw
1 分鐘閱讀時間 (290 個字)

【jQuery】deferred物件介紹及使用deferred物件解決ajax非同步問題

1618728878309

 動機

最近在寫專案時,遇到使用$.when()方法處理ajax非同步問題的情境,這邊把deferred物件整理起來與大家分享。
假如有一個判斷式或後續的程式需要ajax返回的物件:

誤方式
var id1, id2;
$.get("main/func1/").done(function(data1) {
  id1 = data1;
});
$.post("main/func2/","condition").done(function(data2) {
  id2 = data2;
});
alert('id1=' + id1 + ',' + 'id2=' + id2);
執行結果id1跟id2都是undefined。由於ajax是非同步的,ajax還沒返回物件,下面的程式就已經跑完了

使用巢狀ajax的方式
var id1, id2;
$.get("main/func1/").done(function(data1) {
id1 = data1;
  $.post("main/func2/","condition").done(function(data2) {
    id2 = data2;
    alert('id1=' + id1 + ',' + 'id2=' + id2);
  });
});
執行結果id1跟id2雖能取得指定的資料,但若需要2個以上的Ajax,又會繼續巢狀,如此程式也會變得難以維護

使用$.when()
var ajax1 = $.get("main/func1/");
var ajax2 = $.post("main/func2/","condition");
var ajax3 = $.get("main/func3/");
$.when(ajax1,ajax2,ajax3).done(function(id1,id2,id3){
  alert('id1=' + id1 + ',' + 'id2=' + id2 + 'id3=' + id3);
}).fail(function(){ alert('error'); });

$.when()可使用多個deferred物件作為引數,當它們全部執行成功後,才done回撥函式,但只要其中有一個失敗,就呼叫fail回撥函式,關於$.when()下面的介紹會再詳細說明。關於ajax非同步問題可以善用deferred物件處理。

 介紹

Deferred物件

其實平時寫jQuery時使用Ajax的時候,常看到的done()、fail()就是deferred物件。

deferred物件是jQuery對Promises介面的實現。它是非同步操作的通用介面,可以被看作是一個等待完成的任務,開發者通過一些通過的介面對其進行設定。事實上,它扮演代理人(proxy)的角色,將那些非同步操作包裝成具有某些統一特性的物件,典型例子就是ajax操作、網頁動畫、web worker等等。 jQuery的所有Ajax操作函式,預設返回的就是一個deferred物件。

那什麼是Promises?

由於JavaScript單執行緒的特點,如果某個操作耗時很長,其他操作就必需排隊等待。為了避免整個程式失去響應,通常的解決方法是將那些排在後面的操作,寫成回撥函式(callback)的形式。這樣做雖然可以解決問題,但是有一些顯著缺點:

  1. callback往往寫成函式引數的形式,導致函式的輸入和輸出非常混亂,整個程式的可閱讀性差。
  2. 回撥函式通常只能指定單一個,如果有多個操作,就需要改寫回撥函式。
  3. 整個程式的執行流程被打亂,除錯和除錯的難度都相應增加。

Promises就是為了解決這些問題而提出的,它的主要目的就是取代callback,成為非同步操作的解決方案。它的核心思想就是讓非同步操作返回一個物件,其他操作都針對這個物件來完成。比如,假定ajax操作返回一個Promise物件。

var promise = $.get('http://www.testgss.com')

Promise物件有一個then方法,可以用來指定callback。一旦非同步操作完成,就呼叫指定的函式。

$.get('http://www.testgss.com').then(function (content) {
console.log(content)
})

Deferred物件的方法

Deferred的方法其實蠻多種的,如果想要深入了解的話可以參考以下連結。

https://api.jquery.com/category/deferred-object/

這邊舉幾個常用且實用的方法:

$.deferred()可以生成一個deferred物件。

var deferred = $.deferred();

done() 和 fail()

done()指定非同步操作成功後的callback函式;fail()指定失敗後的callback函式。

var deferred = $.Deferred();
deferred
.done(function(value) {
alert(value);
})
.fail(function(value) {
alert(value);
});

它們返回的是原有的deferred物件,因此可以採用鏈式寫法,在後面再連結別的方法(包括done和fail在內)。

resolve() 和 reject()

這兩個方法用來改變deferred物件的狀態。resolve()將狀態改為非同步操作成功,reject()改為操作失敗。

var deferred = $.Deferred();
deferred
.done(function(value) {
alert(value + '-done');
})
.fail(function() {
alert(value + '-fail');
})
.then(function() {
alert(value + '-then')
});
deferred.resolve("resolve");  //  先跳出"resolve-done"再跳出"resolve-then"

一旦呼叫resolve(),就會依次執行done()和then()方法指定的回撥函式;一旦呼叫reject(),就會依次執行fail()和then()方法指定的callback函式。

always()也是指定callback函式,不管是resolve(執行done)或reject(執行fail)都要呼叫。

$.when()方法

$.when()接受多個deferred物件作為引數,當它們全部執行成功後,才呼叫resolved狀態的回撥函式,但只要其中有一個失敗,就呼叫rejected狀態的callback函式。它相當於將多個非同步操作,合併成一個。

$.when(
$.ajax( "/main.php" ),
$.ajax( "/modules.php" ),
$.ajax( "/lists.php" )
).then(function (result1, result2, result3){
console.log(result1);
console.log(result2);
console.log(result3);
});

上面程式碼要等到三個ajax操作都結束以後,才執行then方法指定的回撥函式。回撥函式有三個引數,result1、result2和result3,依次對應前面三個ajax操作的返回結果。
$.when方法的另一個作用是,如果它的引數返回的不是一個Deferred或Promise物件,那麼when方法的回撥函式將立即執行。

javascript使用jsdoc註解並快速產生api文件
一窺倉儲資料的驗證方式

相關文章

 

評論

尚無評論
已經注冊了? 這裡登入
Guest
2024/04/27, 週六

Captcha 圖像