我一直在閱讀有關jQuery遞歸和諾言的文章,但看不到使用.then()
和.done()
進行成功回調的區別。 我知道Eric Hynds提到.done()
和.success()
映射到相同的功能,可是我猜.success()
也是這樣.then()
由於全部回調都在成功完成操做時被調用。 ajax
有人能夠啓發我正確使用嗎? json
返回結果的處理方式也有所不一樣(稱爲連接, 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 })
.done()
終止promise鏈,確保沒有其餘東西能夠附加進一步的步驟。 這意味着jQuery promise實現能夠拋出任何未處理的異常,由於沒有人可使用.fail()
處理它。
實際上,若是您不打算對諾言附加更多步驟,則應使用.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時要調用的處理程序。
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); }
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做爲其結果。
實際上,就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」,而後他們解決了!)