我发现了我正在努力找出的一种行为,但我绝对失去了思路。
当前工作可观察的是:
Observable
.merge(this.eager$, this.lazy$)
.map(() => this.buildURL())
.switchMap(url =>
this.service.getItemsFromSservice(url)
.map(response => this.buildPage(response))
.catch(() => Observable.of(pojo.Page.EMPTY))
);
我的意思是,当由于http通讯错误而引发异常时,该异常将由嵌套的.catch(...)
接收并返回一个空的Page
,并且订阅继续进行,不会出现任何其他问题。
但是,如果我将嵌套的.map(...).catch(...)
移到“主线”链中,则订阅无效:
Observable
.merge(this.eager$, this.lazy$)
.map(() => this.buildURL())
.switchMap(url => this.service.getItemsFromSservice(url))
.map(response => this.buildPage(response))
.catch(() => Observable.of(pojo.Page.EMPTY)
);
使用上述代码,当出现http错误时,订阅将终止。 为什么?
其中:
this.eager$ = Rx.Observable.fromEvent(this.searchButton, 'click');
this.lazy$ = Rx.Observable.fromEvent(this.lazyButton, 'click');
答案 0 :(得分:1)
因为当一个可观察对象发出一个错误时,它永远不会再发出任何东西。错误状态是终端状态。
在第一个代码段中,每次外部可观测对象(由merge()
创建)发出时,switchMap()
都会创建一个新的内部可观测对象。如果此内部观测值发出错误,则将捕获此错误并发出空白页而不是错误。内部可观测对象已达到其最终状态,将不再发出任何信号,但是外部可观测对象从未发出任何错误。如果外部可观测对象发出新事件,则switchMap()
会再次创建一个全新的内部可观测对象。
在第二个代码段中,如果内部可观察对象发出错误,则外部可观察对象的确会发出错误,因为它没有被捕获并被空页面替换。因此,外部可观测对象到达其终端,即错误状态,并且不再发射。
在同步世界中,您可以将其视为两者之间的区别:
for (let i = 0; i < 1000; i++) {
try {
doSomething(i);
}
catch (e) {
// too bad
}
console.log(i);
}
和
try {
for (let i = 0; i < 1000; i++) {
doSomething(i);
}
console.log(i);
}
catch (e) {
// too bad
}
在第一个代码段中,即使doSomething()
抛出异常,也将打印从0到1000的所有数字,因为捕获并忽略了doSomething()抛出的异常。
但是,在第二个异常中,将引发异常,从而中断外部循环。这意味着如果doSomething()
抛出异常,并非所有数字都会被打印。
答案 1 :(得分:0)
问题是主流已经出错,根据rxjs的说法,它不再可用。嵌套的catch有效,因为它只是说getItemsFromSservice
有错误,并且它将继续侦听this.eager$
和this.lazy$
的发射。
也许这行得通,但根本没有测试过:
const page$ = Observable
.merge(this.eager$, this.lazy$)
.map(() => this.buildURL())
.switchMap(url => this.service.getItemsFromSservice(url))
.map(response => this.buildPage(response))
);
this.page$
.catch(() => page$.startWith(pojo.Page.EMPTY))
.subscribe((page) => console.log(page));