我正在努力以我期望的方式处理Rx的错误。
当我有一个可观察对象(例如,从点击流)和一个异常发生,我想抓住它,但继续。我尝试过的所有解决方案都捕获了错误,然后结束了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)
});
虽然由于可观察对象合约(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();
查看JSBin。你在问题中提到的range
Observable是一个冷Observable。它的行为就像一部电影,所以如果发生错误而我们重新订阅,我们需要从"电影"的开头订阅,即1
然后"Error"
。
你可能有一个隐含的假设,即Rx.Observable.range(1, 3)
是一个活动的Observable,即"hot"。因为它不是,我让hotRange
上面使用publish()
。这样,它将独立于其订阅者发出其事件。如果我们希望能够在发生错误后"继续",我们需要源("hotRange")没有错误。这就是为什么range.map( )
不是热门的Observable。retry()
将捕获hotRange.map( )
上的错误并将其替换为hotRange.map( )
。因为hotRange
是热的,所以retry()
的每次执行都会有所不同,因为它不会记住hotRange
之前发出的值。所以在重试中,当2
引起的错误被hotRange.map( )
所取代时,hotRange
随后会发出3
,并且没有错误地传递map函数。