3

问题

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

目标 Observable 的预期行为

  1. 可重试。
  2. 长跑。未完成或出错。
  3. 共享。多个订阅者时不会产生不必要的请求。
  4. 按需加载。未订阅时不会产生不必要的请求。
  5. 将错误通知 UI。

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

我的尝试

我认为最好在继续重试源的同时将错误消息传递给下游观察者。它会对架构造成最小的更改。但是我没有看到可以用 Rxjs 做到这一点的方法,因为

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

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

4

2 回答 2

3

好吧,我似乎在浏览文档时意外找到了答案。

它从使用 的第二个参数开始catchError。根据文档,retrycatchError. 我们可以用较低级别的 来表达更多的逻辑catchError

所以这只是

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

它重试可观察对象,同时向下游观察者发送错误消息。所以下游知道连接错误,并且可以期望接收重试值。

于 2019-09-08T19:30:20.627 回答
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 仍然存在。这看起来有意义吗?

于 2019-09-08T18:03:22.823 回答