1. 程式人生 > >jQuery之Deferred物件詳解

jQuery之Deferred物件詳解

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

jQuery的所有Ajax操作函式,預設返回的就是一個deferred物件。

Promises是什麼

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

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

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

程式碼如下:
var promise = get('http://www.example.com');


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

程式碼如下:
promise.then(function (content) {
  console.log(content)
})


可以將上面兩段程式碼合併起來,這樣程式的流程看得更清楚。

程式碼如下:
get('http://www.example.com').then(function (content) {
  console.log(content)
})

在1.7版之前,jQuery的Ajax操作採用回撥函式。

程式碼如下:
$.ajax({
    url:"/echo/json/",
    success: function(response)
    {
       console.info(response.name);
    }
});

1.7版之後,Ajax操作直接返回Promise物件,這意味著可以用then方法指定回撥函式。

程式碼如下:
$.ajax({
    url: "/echo/json/",
}).then(function (response) {
    console.info(response.name);
});

deferred物件的方法

$.deferred()方法

作用是生成一個deferred物件。

程式碼如下:
var deferred = $.deferred();

done() 和 fail()

這兩個方法都用來繫結回撥函式。done()指定非同步操作成功後的回撥函式,fail()指定失敗後的回撥函式。

程式碼如下:
var deferred = $.Deferred();
deferred.done(function(value) {
   alert(value);
});

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

resolve() 和 reject()

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

程式碼如下:
var deferred = $.Deferred();
deferred.done(function(value) {
   alert(value);
});
deferred.resolve("hello world");


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

state方法

該方法用來返回deferred物件目前的狀態。

程式碼如下:
var deferred = new $.Deferred();
deferred.state();  // "pending"
deferred.resolve();
deferred.state();  // "resolved"


該方法的返回值有三個:

1.pending:表示操作還沒有完成。
2.resolved:表示操作成功。
3.rejected:表示操作失敗。

notify() 和 progress()

progress()用來指定一個回撥函式,當呼叫notify()方法時,該回調函式將執行。它的用意是提供一個介面,使得在非同步操作執行過程中,可以執行某些操作,比如定期返回進度條的進度。

程式碼如下:
 var userProgress = $.Deferred();
    var $profileFields = $("input");
    var totalFields = $profileFields.length
    userProgress.progress(function (filledFields) {
        var pctComplete = (filledFields/totalFields)*100;
        $("#progress").html(pctComplete.toFixed(0));
    }); 
    userProgress.done(function () {
        $("#thanks").html("Thanks for completing your profile!").show();
    });
    $("input").on("change", function () {
        var filledFields = $profileFields.filter("[value!='']").length;
        userProgress.notify(filledFields);
        if (filledFields == totalFields) {
            userProgress.resolve();
        }
    });

then()

then()的作用也是指定回撥函式,它可以接受三個引數,也就是三個回撥函式。第一個引數是resolve時呼叫的回撥函式,第二個引數是reject時呼叫的回撥函式,第三個引數是progress()方法呼叫的回撥函式。

程式碼如下:
deferred.then( doneFilter [, failFilter ] [, progressFilter ] )


在jQuery 1.8之前,then()只是.done().fail()寫法的語法糖,兩種寫法是等價的。在jQuery 1.8之後,then()返回一個新的deferred物件,而done()返回的是原有的deferred物件。如果then()指定的回撥函式有返回值,該返回值會作為引數,傳入後面的回撥函式。

程式碼如下:
var defer = jQuery.Deferred();
defer.done(function(a,b){
            return a * b;
}).done(function( result ) {
            console.log("result = " + result);
}).then(function( a, b ) {
            return a * b;
}).done(function( result ) {
            console.log("result = " + result);
}).then(function( a, b ) {
            return a * b;
}).done(function( result ) {
            console.log("result = " + result);
});
defer.resolve( 2, 3 );

在jQuery 1.8版本之前,上面程式碼的結果是:

程式碼如下:
result = 2 
result = 2 
result = 2 


在jQuery 1.8版本之後,返回結果是

程式碼如下:
result = 2 
result = 6 
result = NaN 


這一點需要特別引起注意。

程式碼如下:
$.ajax( url1, { dataType: "json" } )
.then(function( data ) {
    return $.ajax( url2, { data: { user: data.userId } } );
}).done(function( data ) {
  // 從url2獲取的資料
});

上面程式碼最後那個done方法,處理的是從url2獲取的資料,而不是從url1獲取的資料。

利用then()會修改返回值這個特性,我們可以在呼叫其他回撥函式之前,對前一步操作返回的值進行處理。

程式碼如下:
var post = $.post("/echo/json/")
    .then(function(p){
        return p.firstName;
    });
post.done(function(r){ console.log(r); });


上面程式碼先使用then()方法,從返回的資料中取出所需要的欄位(firstName),所以後面的操作就可以只處理這個欄位了。

有時,Ajax操作返回json字串裡面有一個error屬性,表示發生錯誤。這個時候,傳統的方法只能是通過done()來判斷是否發生錯誤。通過then()方法,可以讓deferred物件呼叫fail()方法。

程式碼如下:
var myDeferred = $.post('/echo/json/', {json:JSON.stringify({'error':true})})
    .then(function (response) {
            if (response.error) {
                return $.Deferred().reject(response);
            }
            return response;
        },function () {
            return $.Deferred().reject({error:true});
        }
    );
myDeferred.done(function (response) {
        $("#status").html("Success!");
    }).fail(function (response) {
        $("#status").html("An error occurred");
    });

always()

always()也是指定回撥函式,不管是resolve或reject都要呼叫。

pipe方法

pipe方法接受一個函式作為引數,表示在呼叫then方法、done方法、fail方法、always方法指定的回撥函式之前,先執行pipe方法指定的回撥函式。它通常用來對伺服器返回的資料做初步處理。

promise物件

大多數情況下,我們不想讓使用者從外部更改deferred物件的狀態。這時,你可以在deferred物件的基礎上,返回一個針對它的promise物件。我們可以把後者理解成,promise是deferred的只讀版,或者更通俗地理解成promise是一個對將要完成的任務的承諾。

你可以通過promise物件,為原始的deferred物件添加回調函式,查詢它的狀態,但是無法改變它的狀態,也就是說promise物件不允許你呼叫resolve和reject方法。

程式碼如下:
function getPromise(){
    return $.Deferred().promise();
}
try{
    getPromise().resolve("a");
} catch(err) {
    console.log(err);
}

上面的程式碼會出錯,顯示TypeError {} 。

jQuery的ajax() 方法返回的就是一個promise物件。此外,Animation類操作也可以使用promise物件。

程式碼如下:
var promise = $('div.alert').fadeIn().promise();

$.when()方法

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

程式碼如下:
$.when(
    $.ajax( "/main.php" ),
    $.ajax( "/modules.php" ),
    $.ajax( "/lists.php" )
).then(successFunc, failureFunc);

上面程式碼表示,要等到三個ajax操作都結束以後,才執行then方法指定的回撥函式。

when方法裡面要執行多少個操作,回撥函式就有多少個引數,對應前面每一個操作的返回結果。

程式碼如下:
$.when(
    $.ajax( "/main.php" ),
    $.ajax( "/modules.php" ),
    $.ajax( "/lists.php" )
).then(function (resp1, resp2, resp3){
    console.log(resp1);
    console.log(resp2);
    console.log(resp3);
});

上面程式碼的回撥函式有三個引數,resp1、resp2和resp3,依次對應前面三個ajax操作的返回結果。

when方法的另一個作用是,如果它的引數返回的不是一個Deferred或Promise物件,那麼when方法的回撥函式將 立即執行。

程式碼如下:
$.when({testing: 123}).done(function (x){
  console.log(x.testing); // "123"
});

上面程式碼中指定的回撥函式,將在when方法後面立即執行。

利用這個特點,我們可以寫一個具有快取效果的非同步操作函式。也就是說,第一次呼叫這個函式的時候,將執行非同步操作,後面再呼叫這個函式,將會返回快取的結果。

程式碼如下:
function maybeAsync( num ) {
  var dfd = $.Deferred();
  if ( num === 1 ) {
    setTimeout(function() {
      dfd.resolve( num );
    }, 100);
    return dfd.promise();
  }
  return num;
}
$.when(maybeAsync(1)).then(function (resp){
  $('#target').append('<p>' + resp + '</p>');
});
$.when(maybeAsync(0)).then(function (resp){
  $('#target').append( '<p>' + resp + '</p>');
});

上面程式碼表示,如果maybeAsync函式的引數為1,則執行非同步操作,否則立即返回快取的結果。

例項

wait方法

我們可以用deferred物件寫一個wait方法,表示等待多少毫秒後再執行。

程式碼如下:
$.wait = function(time) {
  return $.Deferred(function(dfd) {
    setTimeout(dfd.resolve, time);
  });
}


使用方法如下:

程式碼如下:
$.wait(5000).then(function() {
  alert("Hello from the future!");
});

改寫setTimeout方法

在上面的wait方法的基礎上,還可以改寫setTimeout方法,讓其返回一個deferred物件。

程式碼如下:
function doSomethingLater(fn, time) {
  var dfd = $.Deferred();
  setTimeout(function() {
    dfd.resolve(fn());
  }, time || 0);
  return dfd.promise();
}
var promise = doSomethingLater(function (){
  console.log( '已經延遲執行' );
}, 100);

自定義操作使用deferred介面

我們可以利用deferred介面,使得任意操作都可以用done()和fail()指定回撥函式。

程式碼如下:
Twitter = {
  search:function(query) {
    var dfr = $.Deferred();
    $.ajax({
     url:"http://search.twitter.com/search.json",
     data:{q:query},
     dataType:'jsonp',
     success:dfr.resolve
    });
    return dfr.promise();
  }
}

使用方法如下:

程式碼如下:
Twitter.search('intridea').then(function(data) {
  alert(data.results[0].text);
});


deferred物件的另一個優勢是可以附加多個回撥函式。

程式碼如下:
function doSomething(arg) {
  var dfr = $.Deferred();
  setTimeout(function() {
    dfr.reject("Sorry, something went wrong.");
  });
  return dfr;
}
doSomething("uh oh").done(function() {
  alert("Won't happen, we're erroring here!");
}).fail(function(message) {
  alert(message)
}); 轉自:http://www.cnblogs.com/losesea/p/4415676.html

相關推薦

jQueryDeferred物件

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

jQuerydeferred物件

jQuery的開發速度很快,幾乎每半年一個大版本,每兩個月一個小版本。 每個版本都會引入一些新功能。今天我想介紹的,就是從jQuery 1.5.0版本開始引入的一個新功能----deferred物件。 這個功能很重要,未來將成為jQuery的核心方法,它徹底改變了如何在jQuery中使用ajax。為了實現它

Jquery事件委派

spa 性能優化 實現 機制 過濾 event n) function 通過    最近接觸Jquery比較多,今天就被一個Jquery的事件委派坑慘了,特此記錄下,以方便日後的查閱。 一、定義 事件委派的定義就是,把原來加給子元素身上的事件綁定在父元素身上,就是把事件委

jQuery$.ajax()方法

ajax不管是前端,還是後臺都是要學習的知識點,也是必用知識點。ajax是非同步更新,只需要進行少量的資料互動便可到達頁面的區域性刷下。非常棒。 jquery中的ajax方法引數總是記不住,這裡記錄一下。 1.url:  要求為String型別的引數,(預設為當前

jQueryDeferred對象

out filter 角色 string for twitter 1.7 article ech deferred對象是jQuery對Promises接口的實現。它是非同步操作的通用接口,可以被看作是一個等待完成的任務,開發者通過一些通過的接口對其進行設置。事實上,它扮演代

jQuery非同步請求ajax()complete引數

請求完成後回撥函式 (請求success 和 error之後均呼叫)。這個回撥函式得到2個引數:XMLHTTPRequest) 物件和一個描述請求狀態的字串("success", "notmodified", "nocontent","error", "timeout", "abort", 或者 "

ASP內建物件Request物件

來源:網頁教學網 Request物件用於接受所有從瀏覽器發往你的伺服器的請求內的所有資訊。   所有客戶證書的資訊的集合。對於Key,該集合具有如下的關鍵字: Subject 證書的主題。包含所有關

JavaWebRequest物件和Response物件

一:概述 Web伺服器收到客戶端的http請求,會針對每一次請求,分別建立一個用於代表請求的request物件、和代表響應的response物件一、Response物件     1.Resonse的繼承結構:             ServletResponse--Ht

linux awk命令

數學函數 mat loop 多次 finished 數組結構 save pre 新的 awk是一種程序語言,對文檔資料的處理具有很強的功能。awk名稱是由它三個最初設計者的姓氏的第一個字母而命名的: Alfred V. Aho、Peter J. We i n b e rg

運維自動化Saltstack使用

自動化運維 saltstack 概要saltstack是基於Python開發的C/S架構的一款批量管理工具,底層采用動態的連接總線(ZeroMQ消息隊列pub/sub方式通信),使用ssl證書簽發的方式進行認證管理,使其可以用於編配, 遠程執行, 配置管理等等。部署輕松,在幾分鐘內可運行起來,擴展性好

Spark-SqlDataFrame實戰

集合 case 編程方式 優化 所表 register 操作數 print ava 1、DataFrame簡介: 在Spark中,DataFrame是一種以RDD為基礎的分布式數據據集,類似於傳統數據庫聽二維表格,DataFrame帶有Schema元信息,即DataFram

四、python函數

list global pan line ice see war -s span 一、函數 1.說白了就是把一組代碼合到一起,可以實現某種功能,需要再用到這種功能的話,直接調用這個函數就行2.函數、方法是一回事3.定義一個函數的格式是:def+函數名+()4.函數必須調用了

MySQLSELECT 語句

限制 right ont 定義 過程 lar load avg sel 本文參考實驗樓的SELECT 語句詳解結合自己操作部分而寫成。 註意:大多數系統中,SQL語句都是不區分大小寫的,但是出於嚴謹和便於區分保留字和變量名,在書寫的時,保留字應大寫,而變量名應小寫。所謂的保

jQuery.extend 函數

而且 卻又 命名空間 什麽 介紹 常用 new end 空間 JQuery的extend擴展方法: Jquery的擴展方法extend是我們在寫插件的過程中常用的方法,該方法有一些重載原型,在此,我們一起去了解了解。 一、Jquery的擴展方法原型是: 

jQuery Validate驗證框架

lec false 樣式 廈門 adding 常用 invalid util 類名 jQuery校驗官網地址:http://bassistance.de/jquery-plugins/jquery-plugin-validation 一、導入js庫 <scri

spring AOP解析註解方式

parser 分享 pro asp mes aop log space spec 命名空間處理器是AopNamespaceHandler,我們可以看到這裏註冊了幾個解析器,第一個我們知道是xml形式的解析,接下來我們看AspectJAutoProxyBeanDefiniti

jvm學習筆記對象

時間 分代 創建 com 詳解 要求 技術 wid src 一、對象的組成            對象頭(Header):           運行時數據:存儲對象運行時的數據,如哈希碼、GC分代年齡、鎖狀態標誌、線程持有的鎖、偏向線程ID、偏向時間戳等,這部分數據官方成為

【轉】中文分詞HMM模型

實現 含義 jieba 順序 清晰 bsp 中國 matrix 統計 關於HMM模型的介紹,網上的資料已經爛大街,但是大部分都是在背書背公式,本文在此針對HMM模型在中文分詞中的應用,講講實現原理。 盡可能的撇開公式,撇開推導。結合實際開源代碼作為例子,爭取做到雅俗共賞,

[泛型]C# 泛型

如果 runtime 表現 log 都是 元數據 訪問 全面 compare 什麽是泛型 我們在編寫程序時,經常遇到兩個模塊的功能非常相似,只是一個是處理int數據,另一個是處理string數據,或者其他自定義的數據類型,但我們沒有辦法,只能分別寫

Jmockitmock特性

至少 順序 extra xpl replay int 階段 es2017 matcher 本文是Jmockit學習過程中,根據官網所列的工具特性進行解讀。 1、調用次數約束(Invocation count constraints) 可以通過調用計數約束來指定預期和/或允許