2012-06-19 76 views
3

在看了Twisted's Deferred classHeavyLifters Deferred Library之後,我發現如果先前的結果值是Failure類的實例,則會觸發errbacks。這讓我想到:是否有任何特殊原因返回一個特殊的對象來表示一個錯誤,而不是隻是拋出一個錯誤。在異步回調鏈中使用try catch塊返回異常有什麼好處?

據我推斷,我覺得這是更好地拋出,因爲錯誤:

  1. 任何值都可以拋出。
  2. 如果拋出的值沒有被捕獲,它會向上傳播調用堆棧。
  3. 有沒有需要一個特殊的FailureError類。
  4. 它使得回調更像是同步代碼。
  5. 可以在調用堆棧的任何級別處理異常。

一些我注意到的缺點分別爲:

  1. 嘗試的代碼塊和捕獲錯誤可能會導致性能命中的代碼。
  2. 如果未捕獲到異常,則會停止執行回調鏈的其餘部分。
  3. 異步編程是使用try catch塊的極端反面的關鍵。

我想衡量的機率,並找出哪種方法的報告錯誤更適合在這種情況下。

回答

1

Twisted中的Failure類有許多方便使用的方法,與Deferred中用於運行錯誤處理回調的功能無關。瀏覽API文檔,你會發現有用的方法,例如格式化回溯和檢查異常類型。 Failure也是一個非常方便的地方,它可以爲與twisted.internet.defer.inlineCallbacks的生成器以及Cython的特殊支持代碼(其生成微妙的不同例外)獲得很好的集成提供一些真正的重大竅門。

Failure也是一個很好的地方,以追溯狀態與例外一起。 Python異常通常不會攜帶堆棧信息,因此如果您只有一個異常,則無法找出引發的地方。任何時候你想處理髮現它的except塊以外的異常都可能是一個主要缺點。

最後,能夠返回Failure使這個簡單,很常用的模式:

def handleOneErrorCase(reason): 
    if not thisCaseApplies(reason): 
     return reason 

    handleThisCase(reason) 

someDeferred.addErrback(handleOneErrorCase) 

這往往顯示了在Deferred - 使用代碼。這很方便,恰巧在CPython上表現得更好一些,並且還具有保留reason中的原始堆棧信息的優點(如果錯誤處理程序重新提出異常,則處的堆棧將替換掉點原始堆棧,模糊了例外的原始原因)。

0

錯誤通常在異步環境中通過回調返回,因爲無法在異步函數外捕獲錯誤。例如在JavaScript中如果你嘗試:

try { 
    setTimeout(function() { throw new Error(); }, 0); 
} catch (e) { 
    console.log('Caught it.'); 
} 

然後異常將被取消。這與異步函數被重新註冊並隨後被不同堆棧中的事件循環調用並且因此異常不會冒泡原始堆棧的事實有關。

+1

這很明顯。這是因爲函數在'setTimeout'函數中被調用,它捕獲所有錯誤本身。簡單的解決方法是創建一個捕獲所有錯誤並觸發回調的閉包。因此,不是將函數傳遞給'setTimeout',而是傳遞包裝函數的閉包。我真正想知道的是,如果最好在閉包中使用try catch塊或檢查包裝函數的返回值。 –