2015-05-22 49 views
6

我很努力地以我期望的方式處理Rx錯誤。RxJS - 抓住並進行

當我有一個Observable(例如,從一個點擊流),併發生異常我想趕上它,但繼續。我試過的所有解決方案都會發現錯誤,然後結束Observable。有沒有辦法抓住並繼續下去?作爲一個例子,下面的Observable將會發出「1」,然後是「Error」,但不會是「3」。

var range = Rx.Observable.range(1,3) 
    .map(function(i){ 
     if(i === 2){ 
     throw "Error"; 
     } else { 
     return i; 
     } 
    }) 
    .catch(function(e){ 
     return Rx.Observable.return(e) 
    }); 

range.subscribe(function(i){ 
    console.log(i) 
}); 
+0

進行源序列的唯一方法是不要拋出。你能告訴我們你真正的用例是什麼嗎? –

+0

可觀察的契約是它必須向觀察者發出模式:(OnNext)*(OnCompleted | OnError)。所以一個序列發出OnError的那一刻就結束了。 –

+0

@OliverWeichhold真正的案例是一個Click事件observable,其中'flatMap()'指向一個http請求observable。如果/當http請求失敗時,click click不再發光。 – MaxWillmo

回答

9

當你預期的行爲,不能因爲合同(OnNext)* (OnCompleted|OnError)可觀測的實現,也有解決這個正常工作通過引入熱可觀察實際的方式。

let hotRange = Rx.Observable.range(1,3).publish(); 

let safeRange = hotRange 
    .map(function (i) { 
    if (i === 2) { 
     throw "Error"; 
    } else { 
     return i; 
    } 
    }) 
    .retry(); 

safeRange.subscribe(i => console.log(i)); 
hotRange.connect(); 

See the JSBin。你在問題中提到的Observable是一個冷的Observable。它behaves as a movie,所以如果發生錯誤,我們重新訂閱,我們需要訂閱從「電影」開始,即1然後"Error"

您可能有一個隱含的假設,即Rx.Observable.range(1, 3)是一個實時Observable,即「熱」。由於它不是,我使用publish()來製作hotRange。通過這種方式,它將獨立於用戶發佈其事件。如果我們希望能夠在錯誤發生後「繼續」,我們需要我們的源代碼(「hotRange」)沒有錯誤。這就是爲什麼range.map()不是熱的Observable。 retry()將在hotRange.map()上發現錯誤並將其替換爲hotRange.map()。因爲hotRange很熱,所以每次執行retry()都會有所不同,因爲它不記得hotRange發出的以前的值。所以當2在重試中被hotRange.map()取代時,hotRange隨後會發出3,並且傳遞map函數沒有錯誤。

+0

這是有道理的,如果只會有一個例外。在n-case'retry'中工作可能會更好,而不是'catch'。 – paulpdaniels

+0

好點。我更新了答案。謝謝 –

+0

@AndréStaltz。但是在訂閱方法中,錯誤處理程序不會發出任何東西。我們怎樣才能在錯誤處理程序中發生錯誤? – xgrommx