Rxjs Observable:只为第一个订阅者获取 HTTP 数据,为其余订阅者获取缓存数据

Rxjs Observable: Get HTTP data only for the first subscriber and cached data for the rest

我正在尝试在 Angular 应用程序中实现用户权限,但简单来说,就是这样的场景:

加载 MainModule 后,我发出 HTTP 请求并将数据存储在 localStorage 中,以便下次我可以从那里检索数据。这个逻辑在 Observable 中,我从几个地方订​​阅它。

问题是,如果同时执行两个订阅,我什至没有机会将数据存储到 localStorage 之前就会发出两个 HTTP 请求。

就是这样,但要进一步解释...

我只想发出一次 HTTP 请求,将数据存储在 localStorage 中并发出值,从第二个订阅者开始,如果可能,忽略所有这些逻辑,只 return 最后一个发射值。

我尝试使用 BehaviorSubject,但是当我重新进入模块时我得到了最后发出的数据(即 user_A 注销user_B 登录)。我正在使用的服务在 root 中提供,我无法在 MainModule 中提供它,因为我在那里的一些守卫出现 DI 错误。我还阅读了 share 运算符,但我不太确定如何使用它。

更新(添加到@Nugu's ):

share 的问题是管道 observable 没有完成,所以我在 Observable 中封装了一个调用 .next(value).complete() 的订阅 this.http.get<T> ,现在它正在工作。我在发出HTTP请求之前还添加了localStorage的条件。

此外,在每个模块重新进入时,我仍然得到最后发射的值,所以我将函数 getSomeData() 变成 属性 以始终获得相同的 Observable 实例。

使用 share() 运算符在多个订阅者之间共享源。这将确保响应在许多订阅者之间共享并防止重复的 HTTP 请求。

getSomeData(): Observable<any> {
  return this.http.get<any>('/endpoint').pipe(share());
}

您可以在调用 getSomeData() 之前执行 if 条件以检查数据是否已在商店中可用。

我不确定这是否实用,但我喜欢分享。 首先你还需要1个主题

 loggingIn: BehaviorSubject<boolean> = new BehaviorSubject<boolean>(null);

然后在 login() 服务内部触发状态

 login(): void {
   this.loggingIn.next(true);
   // ....loging
   this.loggingIn.next(false);
 }

所以getUser()看起来像这样

 getUser(): Observable<User> {
   return this.loggingIn.pipe(() => {
     return this.user.pipe(filter(user => user !== null));
   });
 }