Rxjs-如何在通知UI错误的同时重试可观察到的错误

时间:2019-09-08 16:23:34

标签: rxjs rxjs6 reactivex data-layers

问题

假设有一个可观察到的Http请求出错,我们可以重试它。但我也希望UI通知用户该资源无法加载。最好的架构是什么?

可观察目标的预期行为

  1. 可重试。
  2. 长时间运行。没有完成或出错。
  3. 已共享。当多个订户时,不会产生不必要的请求。
  4. 按需加载。未订阅时不会生成不必要的请求。
  5. 将错误通知UI。

shareReplay({bufferSize: 1, refCount: true})可以实现3和4)

我的尝试

我认为最好在继续重试源代码的同时将错误消息传递给下游观察者。它对体系结构的更改最少。但是我没有找到使用Rxjs的方法,因为

  1. retry()总是拦截错误。如果出现错误,则retry()将不会重试。如果没有,则不会有错误传播到下游。
  2. catchError()而无需重新抛出将始终完成流。

尽管让UI观察者tap(,,onError)retry()可以满足这一需求,但是我认为让UI承担这一责任很危险。而且,多个UI观察者意味着很多重复的重试。

2 个答案:

答案 0 :(得分:1)

听起来您正在寻找类似于NgRx副作用的东西。您可以将它们全部封装在外部Observable中,将错误处理程序传递给内部Observable(您的HTTP调用),如下所示:

const myObs$ = fromEvent('place event that triggers call here').pipe(
               // just one example, you can trigger this as you please
  switchMap(() => this.myHttpService.getResource().pipe(
    catchError(err => handleAndRethrowError()),
    retry(3)
  ),
  shareReplay()
);

这样,如果请求引发错误,它将重试3次(catchError块中有错误处理,即使完全出错,外部Observable仍然有效。看起来像有道理吗?

答案 1 :(得分:1)

好吧,我似乎在浏览文档时不小心找到了答案。

首先使用catchError的第二个参数。根据文档,retrycatchError实现。而且我们可以使用较低级别的catchError表达更多的逻辑。

就这样

catchError((err, caught) => {
  return timer(RETRY_DELAY_TIME).pipe(
    mergeMap(() => caught)
    startWith(err)
  );
})

它重试可观察到的内容,同时向下游观察者发送错误消息。因此,下游知道连接错误,并且可以期望接收重试的值。