[翻譯]在jQuery 1.5中使用deferred對象

原文:http://www.erichynds.com/jquery/using-deferreds-in-jquery/jquery

翻譯:三生石上(http://cnblogs.com/sanshi/ajax

 

譯者注:數組

1. Deferred是jQuery1.5新增的一個特性,不少人把它翻譯成 「異步隊列」,我以爲比較靠譜,畢竟和「延遲」沒啥關係,不過這篇文章中我還採用deferred這個單詞。promise

2. 這篇文章在jQuery1.5發佈博客中提到,也是目前介紹deferred比較經典和深刻的文章。鑑於目前中文資料比較少,特別翻譯出來供你們學習參考。服務器

3. 通篇採用意譯的方式,若有不當還請你們提出。併發

 

 

jQuery1.5中新增的Deferreds對象,能夠將任務完成的處理方式與任務自己解耦合。這在JavaScript社區沒什麼新意,由於Mochikit和Dojo兩個JS框架已經實現了這個特性很長一段時間了。可是隨着Julian Aubourg對jQuery1.5中AJAX模塊的重寫,deferreds理所固然成爲了內部的實現邏輯。使用deferreds對象,多個回調函數能夠被綁定在任務完成時執行,甚至能夠在任務完成後綁定這些回調函數。這些任務能夠是異步的,也能夠是同步的。框架

更重要的是,deferreds已經做爲$.ajax()的內部實現,因此你能夠在調用AJAX時自動獲取deferreds帶來的遍歷。好比咱們能夠這樣綁定回調函數:異步

// $.get, 異步的AJAX請求函數

var req = $.get('foo.htm').success(function (response) {學習

    // AJAX成功後的處理函數

}).error(function () {

    // AJAX失敗後處理函數

});

 

// 這個函數有可能在AJAX結束前調用

doSomethingAwesome();

 

// 添加另一個AJAX回調函數,此時AJAX或許已經結束,或許尚未結束

// 因爲$.ajax內置了deferred的支持,因此咱們能夠這樣寫

req.success(function (response) {

    // 這個函數會在AJAX結束後被調用,或者當即被調用若是AJAX已經結束

});

咱們再也不被限制到只有一個成功,失敗或者完成的回調函數了。相反這些隨時被添加的回調函數被放置在一個先進先出的隊列中。

從上面例子看出,回調函數能夠被附加到AJAX請求中(任何可觀察的任務observable task),甚至在AJAX請求已經結束。對於代碼的組織是很好的,咱們不再用寫很長的回調函數了。這就像$.queue()遇到了pub/sub(發佈訂閱機制,通常用在基於事件處理的模型中).

更深刻一些,想象這樣一個場景,在一些併發的AJAX請求所有結束以後執行一個回調函數。我能夠方便的經過jQuery的函數$.when()來完成:

function doAjax() {

    return $.get('foo.htm');

}

 

function doMoreAjax() {

    return $.get('bar.htm');

}

 

$.when(doAjax(), doMoreAjax()).then(function () {

    console.log('I fire once BOTH ajax requests have completed!');

}).fail(function () {

    console.log('I fire if one or more requests failed.');

});

在jsFiddle中打開示例

 

上面的示例可以正常運行,這要歸功於每一個jQuery的AJAX方法返回值都包含一個promise函數,用來跟蹤異步請求。Promise函數的返回值是deferred對象的一個只讀視圖。(The promise is a read-only view into the result of the task.Deferreds經過檢測對象中是否存在promise()函數來判斷當前對象是否可觀察。$.when()會等待全部的AJAX請求結束,而後調用經過 .then(), .fail()註冊的回調函數(具體調用哪些回調函數取決於任務的結束狀態)。這些回調函數會按照他們的註冊順序執行。

更好的是,$.when()接受函數或者函數的數組爲參數(譯者注:這點不大對,$.when接受一個或多個deferred對象,或者原生的JS對象。注意不能以函數數組爲參數),這樣你就能夠隨意組合這些異步任務。

$.ajax()返回一個對象,這個對象關聯一些deferred函數,好比promise(), then(), success(), error()。然而你不能操做原始的deferred對象,只有promise()函數(譯者注:還記得剛纔提到的promise是隻讀視圖),以及能夠檢測deferred狀態的isRejected() 以及isResolved()函數。

可是爲何不返回deferred對象呢?若是返回了完整的deferred對象,那麼咱們就擁有更多的控制,或許能夠隨意的觸發(譯者注:我把resolve翻譯成觸發,就是觸發全部註冊到deferred對象上的回調函數)deferred對象,從而致使全部回調函數在AJAX請求結束以前執行。所以,爲了不不指望的觸發deferred的風險,咱們應該只返回dfd.promise().(Therefore, to avoid potentially breaking the whole paradigm, only return the dfd.promise().)(譯者注:若是你很迷惑上面幾段話的確切意思,不要緊,我隨後會寫一篇文章深層次分析其中緣由:http:/cnblogs.com/sanshi/

註冊回調函數(Registering Callbacks)

上面的例子中,咱們使用then(), success(), fail()方法來註冊回調函數,其實還有更多的方法可使用,特別在處理AJAX請求時。具體使用哪一種方式取決於你對結果狀態的關注。

全部deferred對象都有的函數 (AJAX, $.when 或者手工建立的deferred對象):

.then( doneCallbacks, failedCallbacks )

.done( doneCallbacks )

.fail( failCallbacks )

AJAX對象包含3個額外的方法,其中兩個會映射到上面提到的方法。這些方法主要是爲了兼容之前的代碼:

// "success"  "error" 會分別映射到 "done" and "fail" 兩個方法

.success( doneCallbacks )

.error( failCallbacks )

你也能夠註冊一個complete的回調函數,它會在請求結束後調用,而無論這個請求是成功或者失敗。不像success或者error函數,complete函數實際上是一個單獨的deferred對象的done函數別名。這個在$.ajax()內部建立的deferred對象,會在AJAX結束後觸發回調函數(resolve)。

.complete( completeCallbacks )

所以,下面的3個例子是等價的(在AJAX的上下文中,success看起來比done函數會舒服點,對麼?)(譯者注:實際上是由於咱們熟悉之前的AJAX調用方式,先入爲主罷了,或者叫思惟定勢):

$.get("/foo/").done( fn );

// 等價於:

$.get("/foo/").success( fn );

// 等價於:

$.get("/foo/", fn );

建立本身的deferred對象(Creating your own Deferred

咱們知道$.ajax和$.when在內部實現了deferred接口,不過咱們也能夠手工建立deferred對象:

function getData() {

    return $.get('/foo/');

}

 

function showDiv() {

    var dfd = $.Deferred();

    $('#foo').fadeIn(1000, dfd.resolve);

    return dfd.promise();

}

 

$.when(getData(), showDiv()).then(function (ajaxResult) {

    console.log('The animation AND the AJAX request are both done!');

    // 'ajaxResult'是服務器端返回(譯者注:也就是getDataAJAX的結果)

});

在jsFiddle中打開示例

在showDiv()中,咱們建立了一個deferred對象,執行了一段動畫,而後返回promise。這個deferred對象會在fadeIn()結束後被觸發(resolved)。在這個promise返回和deferred對象(注意:這裏的deferred指的是$.when建立的對象,而非showDiv()返回的對象)觸發的中間,一個then()回調函數會被註冊。這個回調函數會在兩個異步的任務所有結束後執行。

getData()返回一個對象(譯者注:實際上是jQuery封裝的XMLHttpRequest對象)擁有promise方法,這就容許$.when()監視本次AJAX請求的結束。The manually steps we took to return a promise in showDiv() is handled for us internally by $.ajax() and $.when().

1/15/2011: Julian在評論中指出,上面的語法能夠被簡化爲$.Deferred(fn).promise()。所以下面的兩端代碼是等價的:

 

function showDiv() {

    var dfd = $.Deferred();

    $('#foo').fadeIn(1000, dfd.resolve);

    return dfd.promise();

}

// 等價於:

function showDiv() {

    return $.Deferred(function (dfd) {

        $('#foo').fadeIn(1000, dfd.resolve);

    }).promise();

}

 

爲自定義的deferred對象添加回調函數(Defer your Deferreds

咱們能夠更進一步,爲getData()和showDiv()分別註冊回調函數,如同咱們在$.then()中註冊回調函數同樣。(譯者注:下面的段落內容重複,說的都是一個意思,就不翻譯了,看代碼吧)

function getData() {

    return $.get('/foo/').success(function () {

        console.log('Fires after the AJAX request succeeds');

    });

}

 

function showDiv() {

    return $.Deferred(function (dfd) {

        // 譯者注:這段代碼是原文沒有的,可是在jsFiddle中出現。

        // 我以爲這是做者的原意,爲自定義的deferred函數註冊回調函數

        dfd.done(function () {

            console.log('Fires after the animation succeeds');

        });

        $('#foo').fadeIn(1000, dfd.resolve);

    }).promise();

}

 

$.when(getData(), showDiv()).then(function (ajaxResult) {

    console.log('Fires after BOTH showDiv() AND the AJAX request succeed!');

    // 'ajaxResult'是服務器返回結果

});

在jsFiddle中打開示例

相關文章
相關標籤/搜索