【问题标题】:RxJS: Nested catch vs raw catchRxJS:嵌套捕获与原始捕获
【发布时间】:2019-05-09 17:13:02
【问题描述】:

我发现了一个我正在努力弄清楚的行为,但我确实迷失了思路。

当前工作可观察到的是:

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');

【问题讨论】:

  • 如我的另一个答案stackoverflow.com/questions/56041453/… 所示,在嵌套捕获中,我没有返回错误,因此流继续。如果我返回一个错误,即使在那种情况下它也会停止。 当您返回 Observable.of(pojo.Page.EMPTY) 时,这是成功的,如果您返回 Observable.throw(pojo.Page.EMPTY) 您的流将停止了

标签: angular typescript rxjs


【解决方案1】:

因为当一个 observable 发出错误时,它永远不会再发出任何东西。错误状态是终端状态。

在第一个 sn-p 中,每次外部 observable(由 merge() 创建)发出时,switchMap() 创建一个新的内部 observable。如果此内部观察发出错误,则捕获此错误并发出一个空页面而不是错误。内部的 observable 已经达到了它的最终状态并且永远不会再次发出,但是外部的 observable 从来没有发出任何错误。如果外部 observable 发出一个新事件,那么 switchMap() 会再次创建一个全新的内部 observable。

在第二个 sn-p 中,如果内部 observable 发出错误,则外部 observable 确实会发出错误,因为它没有被捕获并被空页面替换。所以外部的 observable 到达了它的终端,错误状态并且不再发射。

在一个同步的世界里,你可以把它看作是这之间的不同:

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
}

在第一个 sn-p 中,即使doSomething() 抛出异常,也会打印从 0 到 1000 的所有数字,因为 doSomething() 抛出的异常被捕获并忽略。

然而,在第二个中,异常被抛出,因此中断了外部循环。这意味着如果doSomething() 抛出异常,则不会打印所有数字。

【讨论】:

    【解决方案2】:

    问题是主流出错了,根据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));
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-18
      • 2016-05-30
      • 2012-04-15
      • 2020-05-23
      • 2019-10-14
      相关资源
      最近更新 更多