我是Rx的新手,我非常感谢错误处理方面的一些帮助。我有以下代码,基本上是一个类型:
var observable = Rx.Observable.fromEvent(searchField, 'keyup')
.map(ev => ev.target.value)
.filter(text => text.length > 2)
.debounce(500 /* ms */)
.distinctUntilChanged()
.flatMapLatest(getAsyncSearchResults);
observable.subscribe(function(value) {
console.log("onNext");
throw "error"; // THIS TERMINATES THE OBSERVABLE
},
function(error) {
console.log("Error");
},
function() {
console.log("Completed");
});
在onNext函数发生异常后,Observable终止。这对我来说似乎是一个不受欢迎的行为,因为我不想将所有的onNext代码包装在try-catch中。有什么方法可以告诉观察者不管发生什么异常都会发出通知吗?
答案 0 :(得分:2)
您应该确保next
,completed
和error
处理程序对例外安全。源流没有合理的方式来恢复"订阅者错误时的订阅 - 唯一合理的做法是停止与订阅者交谈。
有关为什么会看到我的答案How to handle exceptions thrown by observer's onNext in RxJava?的完整讨论 - 这同样适用于Rx的任何平台实现。
此外,请参阅Why is the OnError callback never called when throwing from the given subscriber?以获得考虑因素的良好解释性比喻(新闻报道) - 尤其需要考虑可能其他订阅者未在其{{ {1}}处理程序。
答案 1 :(得分:2)
您需要切换到新的一次性流,如果在其中发生错误,将安全地处理,并保持原始流的活动。
我已将您的代码修改为更简单的0 - 5流,以便轻松演示。如果数字为3,则抛出错误/异常。
Rx.Observable.from([0,1,2,3,4,5])
.switchMap(value => {
// This is the disposable stream!
// Errors can safely occur in here without killing the original stream
return Rx.Observable.of(value)
.map(value => {
if (value === 3) {
throw new Error('Value cannot be 3');
}
return value;
})
.catch(error => {
// You can do some fancy stuff here with errors if you like
// Below we are just returning the error object to the outer stream
return Rx.Observable.of(error);
});
})
.map(value => {
if (value instanceof Error) {
// Maybe do some error handling here
return `Error: ${value.message}`;
}
return value;
})
.subscribe(
(x => console.log('Success', x)),
(x => console.log('Error', x)),
(() => console.log('Complete'))
);
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.4.1/Rx.min.js"></script>
此博客文章中有关此技术的更多信息:The Quest for Meatballs: Continue RxJS Streams When Errors Occur
答案 2 :(得分:0)
这就是Rx在每个平台上的行为,而在观察者中捕获异常的唯一方法就是......好吧......抓住它们。
您可以创建自己的subscribeSafe
方法,如果您经常需要,可以在try / catch中包装回调。
或者,如果您可以将从观察者投掷的部分移动到流本身,则可以控制错误流,并(例如)重试。
以下示例:
// simulates (hot) keyup event
const obs1 = Rx.Observable.interval(1000).publish()
obs1.connect()
function getAsyncSearchResults(i) {
return Rx.Observable.timer(500).mapTo(i)
}
obs1.switchMap(getAsyncSearchResults).do(x => {
console.log(x) // all events gets logged
throw new Error()
}).retry().subscribe()
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/rxjs/5.0.2/Rx.js"></script>
&#13;