2014-06-18 125 views
1

雖然使用javascript異步錯誤掛機構打,我最後問自己,什麼是使用一個承諾,而不是回調的區別,旁邊的事實,承諾是,也許更多的糖句法。回調還是承諾?

例如,讓我們考慮

 function setPromise() { 
      var message = "awesome"; 
      var deferred = new $.Deferred(); 
      setTimeout(function(){deferred.resolve(message)},3000); 
      return deferred.promise(); 
     } 

     var promise = setPromise(); 

     promise.done(function (message) { 
      console.log("promise done with message : " + message); 
     }); 

 function setCallback(doneCallback) { 
      var message = "awesome"; 
      setTimeout(function(){doneCallback(message)},3000); 
     } 

     setCallback(callback) 

     function callback(message) { 
      console.log("callback done with message : " + message); 
     } 

均用作封,都允許參數被送回等

那麼有什麼區別?

+1

Promises在自己的實現中使用回調函數,但也支持更多的功能,例如處理程序的鏈接,異步完成/錯誤通知的標準化接口等等。這有點像說功能和OOP之間有什麼區別,一個是低層構造 - 另一個是使用相同低層構造的更多功率機制,但也支持更多功能和可擴展性。承諾的真正威力來自您需要進行序列化或協調的多個異步操作。 – jfriend00

回答

4

承諾是建立在回調的頂部。後者更原始,更一般,當你需要做一些複雜的事情時需要更多的工作。

對於你的榜樣,他們做的是幾乎同樣的事情。但是,假設您想同時解決三件事情(想象一下同時需要AJAX提供三種資源),並在三件事完成時繼續。承諾是微不足道的,因爲基本上沒有什麼變化。但通過回調,你需要設置一些標誌/計數器,並且自己識別成功和失敗狀態 - 更多的工作。

3

語義,實乃的兩段代碼之間沒有真正的區別。消息在調用初始函數後的某個時間提供給回調函數。

從設計的角度來看,人們傾向於承諾,因爲他們通常會導致更容易執行代碼。在回調處理某些長時間運行的函數的結果時,尤其如此。考慮以下兩個慢速運行的功能:

var slowlyReturn1 = function (callback) { 
    window.setTimeout(callback.call(1), 1000); 
} 

var slowlyReturn2 = function (callback) { 
    window.setTimeout(callback.call(2), 1000); 
} 
使用這兩個長期運行的功能的結果

寫代碼是很毛毛:

slowlyReturn1(function(resultOf1) { 
    slowlyReturn2(function(resultOf2) { 
    console.log("results were: " + resultOf1 + " and " + resultOf2); 
    }) 
}); 

請注意,在長鏈各個環節運行功能導致另一個嵌套級別。隨着承諾的代碼,你往往不會有這樣的問題:

var slowlyReturn1 = function() { 
    var d = $.Deferred(); 
    window.setTimeout(function() { d.resolve(1) }, 1000); 
    return d.promise(); 
} 

var slowlyReturn2 = function() { 
    var d = $.Deferred(); 
    window.setTimeout(function() { d.resolve(2) }, 1000); 
    return d.promise(); 
} 

var resultOf1; 

slowlyReturn1().then(function(r) { 
    resultOf1 = resultOf1; 
    return slowlyReturn2(); 
}).then(function(resultOf2) { 
    console.log("results were: " + resultOf1 + " and " + r); 
}); 

而且,與承諾的代碼,也往往是關注清晰分離。執行慢速運行操作的代碼不知道結果將如何使用:它只是返回表示延遲結果並讓調用方處理它的內容。

你對付它的一個很好的應用設計環繞異常處理。緩慢運行的操作可能是.resolve()的承諾,但他們也可能在出現問題的地方出現.reject()。這可以拒絕使用.fail()如下處理:

slowRunningOperations().then(function() { 
    ... 
    ... 
    ... handle success 
    ... 
    ... 
}).fail(function() { 
    ... 
    ... handle failure 
    ... 
    ... 
}) 

這裏,運行慢的操作的調用者並不關心錯誤,它可以簡單地忽略它們。

有承諾編程其他幾個好處:

  • 支持的承諾提供了一種方法來治療這兩種常規功能和返回一個承諾以同樣的方式的功能大多數圖書館。他們通常通過提供名爲when()的功能來實現此目的。這爲測試承諾代碼提供了一個非常好的方法,或者允許將慢速函數更改爲影響調用者的promise-returning-one w/o。

  • 支持承諾的大多數庫還提供了使用承諾模擬更傳統的控制流的功能。例如,Q庫提供allSettled(list),它接受承諾列表並返回一個承諾,該承諾在列表中的所有承諾都完成時解決。

也就是說,正如另一個答案所述,承諾會帶來一點開銷。如果你沒有進行強化鏈接或錯誤處理,或者嚴格按照控制流使用回調,那麼只需傳遞函數即可。