jQuery的延遲和承諾-.then()與.done()

我一直在閱讀有關jQuery遞歸和諾言的文章,但看不到使用.then().done()進行成功回調的區別。 我知道Eric Hynds提到.done().success()映射到相同的功能,可是我猜.success()也是這樣.then()由於全部回調都在成功完成操做時被調用。 ajax

有人能夠啓發我正確使用嗎? json


#1樓

返回結果的處理方式也有所不一樣(稱爲連接, done不連接, then生成調用鏈) 數組

promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);
    return 123;
}).then(function (x){
    console.log(x);
}).then(function (x){
    console.log(x)
})

將記錄如下結果: promise

abc
123
undefined

服務器

promise.done(function (x) { // Suppose promise returns "abc"
    console.log(x);
    return 123;
}).done(function (x){
    console.log(x);
}).done(function (x){
    console.log(x)
})

將獲得如下內容: app

abc
abc
abc

----------更新: 異步

順便說一句。 我忘了提一下,若是您返回一個Promise而不是原子類型值,則外部諾言將等到內部諾言獲得解決: ide

promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);
    return $http.get('/some/data').then(function (result) {
        console.log(result); // suppose result === "xyz"
        return result;
    });
}).then(function (result){
    console.log(result); // result === xyz
}).then(function (und){
    console.log(und) // und === undefined, because of absence of return statement in above then
})

這樣,編寫並行或順序異步操做變得很是簡單,例如: 函數

// Parallel http requests
promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);

    var promise1 = $http.get('/some/data?value=xyz').then(function (result) {
        console.log(result); // suppose result === "xyz"
        return result;
    });

    var promise2 = $http.get('/some/data?value=uvm').then(function (result) {
        console.log(result); // suppose result === "uvm"
        return result;
    });

    return promise1.then(function (result1) {
        return promise2.then(function (result2) {
           return { result1: result1, result2: result2; }
        });
    });
}).then(function (result){
    console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
    console.log(und) // und === undefined, because of absence of return statement in above then
})

上面的代碼並行發出兩個http請求,從而使請求更快完成,而下面的那些http請求則按順序運行,從而減小了服務器負載 post

// Sequential http requests
promise.then(function (x) { // Suppose promise returns "abc"
    console.log(x);

    return $http.get('/some/data?value=xyz').then(function (result1) {
        console.log(result1); // suppose result1 === "xyz"
        return $http.get('/some/data?value=uvm').then(function (result2) {
            console.log(result2); // suppose result2 === "uvm"
            return { result1: result1, result2: result2; };
        });
    });
}).then(function (result){
    console.log(result); // result === { result1: 'xyz', result2: 'uvm' }
}).then(function (und){
    console.log(und) // und === undefined, because of absence of return statement in above then
})

#2樓

.done()終止promise鏈,確保沒有其餘東西能夠附加進一步的步驟。 這意味着jQuery promise實現能夠拋出任何未處理的異常,由於沒有人可使用.fail()處理它。

實際上,若是您不打算對諾言附加更多步驟,則應使用.done() 。 有關更多詳細信息,請參見爲何須要兌現承諾


#3樓

deferred.done()

添加僅在Deferred解決後才調用的處理程序。 您能夠添加多個要調用的回調。

var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).done(doneCallback);

function doneCallback(result) {
    console.log('Result 1 ' + result);
}

您也能夠像上面這樣寫

function ajaxCall() {
    var url = 'http://jsonplaceholder.typicode.com/posts/1';
    return $.ajax(url);
}

$.when(ajaxCall()).then(doneCallback, failCallback);

deferred.then()

添加要解析,拒絕或仍在進行中的Deferred時要調用的處理程序。

var url = 'http://jsonplaceholder.typicode.com/posts/1';
$.ajax(url).then(doneCallback, failCallback);

function doneCallback(result) {
    console.log('Result ' + result);
}

function failCallback(result) {
    console.log('Result ' + result);
}

#4樓

then()始終表示在任何狀況下都將調用它。 可是在不一樣的jQuery版本中傳遞的參數是不一樣的。

在jQuery 1.8以前, then()等於done().fail() 。 而且全部回調函數共享相同的參數。

可是從jQuery 1.8開始, then()返回一個新的promise,若是它返回一個值,它將被傳遞到下一個回調函數中。

讓咱們看下面的例子:

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( 3, 4 );

在jQuery 1.8以前,答案應該是

result = 3
result = 3
result = 3

全部result均爲3。then then()函數始終將相同的延遲對象傳遞給下一個函數。

可是從jQuery 1.8開始,結果應該是:

result = 3
result = 7
result = NaN

由於第一個then()函數返回一個新的promise,而且值7(這是將傳遞的惟一參數)被傳遞到下一個done() ,因此第二個done()寫入result = 7 。 第二個then()a的值做爲7,將undefined做爲b的值,所以第二個then()返回帶有參數NaN的新諾言,最後一個done()打印NaN做爲其結果。


#5樓

實際上,就jQuery的Deferreds而言,它是Promises的實現(實際上jQuery3.0試圖將它們歸入規範),這之間存在着至關關鍵的區別。

完成/而後之間的主要區別是

  • .done()始終返回與開始時相同的Promise / wrapped值,不管您作什麼或返回什麼。
  • .then()始終返回一個新的Promise,而您負責根據您傳遞給它的函數返回的內容來控制Promise的內容。

.done()從jQuery轉換爲本地ES2015 Promises,有點像在Promise鏈中圍繞函數實現「 tap」結構,若是鏈處於「 resolve」狀態,它將傳遞一個值給一個函數...可是該函數的結果不會影響鏈自己。

const doneWrap = fn => x => { fn(x); return x };

Promise.resolve(5)
       .then(doneWrap( x => x + 1))
       .then(doneWrap(console.log.bind(console)));

$.Deferred().resolve(5)
            .done(x => x + 1)
            .done(console.log.bind(console));

這些都將記錄5,而不是6。

請注意,我使用done和doneWrap進行日誌記錄,而不是.then。 那是由於console.log函數實際上不返回任何東西。 若是傳遞.then函數不返回任何內容,會發生什麼?

Promise.resolve(5)
       .then(doneWrap( x => x + 1))
       .then(console.log.bind(console))
       .then(console.log.bind(console));

這將記錄:

5

未定義

發生了什麼? 當我使用.then並將其傳遞給一個不返回任何內容的函數時,它的隱式結果是「未定義」 ...固然,該結果固然將Promise [undefined]返回給下一個then方法,該方法記錄了未定義。 所以,咱們開始時的原始價值基本上已經丟失。

.then()是函數組合的一種形式:每一個步驟的結果都用做下一步中該函數的參數。 這就是爲何最好將.done視爲「敲擊」->它實際上不是組合的一部分,而只是在某個步驟中偷偷看了一下值並以該值運行功能,但實際上並無改變以任何方式組成。

這是一個很是根本的差別,而且極可能有一個很好的理由,爲何本機Promises自己沒有實現.done方法。 咱們無需深刻探討爲何沒有.fail方法,由於這更加複雜(即,.fail / .catch不是.done / .then的鏡像,.catch中返回裸值的函數不會像傳遞給.the的那些人同樣拒絕了「 stay」,而後他們解決了!)

相關文章
相關標籤/搜索