首页 > 解决方案 > 有人能解释一下为什么 BehaviorSubject 结果会这样吗?

问题描述

我编写了一个服务,其中包含一个名为 loginStatus 的 BehaviorSubject 和一个返回它的函数。

private loginStatus = new BehaviorSubject<boolean>(false);

getLoginStatus(): Observable<boolean> {
  return this.loginStatus;
}

然后我在其他组件的 DOM 中使用 4 个不同 div 中的异步管道订阅它,我只是评论了 shareReplay 以显示我想知道的内容。

  loginStatus$ = this.authService.getLoginStatus().pipe(
    switchMap(res => {
      if (!res) { return this.authService.isLoggedIn(); }
      else { return of(res); }
    }),
    tap(res => console.log('tap: ' + res)),
    //shareReplay(1),
 );

isLoggedIn 是一个 http 请求,用于检查我是否登录,我检查 switchMap 中的 loginStatus 值,如果它是 false 则调用 isLoggedIn

isLoggedIn(): Observable<boolean> {
console.log('called isLoggedIn');
return this.httpService.get('/auth/isLoggined').pipe(
  map(res => {
    console.log('isLoggedIn res: ' + JSON.stringify(res));
    if (res) {
      this.loginStatus.next(true);
      this.firstName = res.first_name;
      this.lastName = res.last_name;
      this.tel = res.tel;
      return 'fool';
    } else {
      this.clearAll();
      return false;
    }
  }),

最后这是我的控制台结果:

called isLoggedIn
called isLoggedIn
called isLoggedIn
called isLoggedIn

由于我的 4 个异步管道,isLoggedIn 被调用了 4 次,并且 loginStatus 为 false。

在第一个 http 请求响应时,我得到了一个像 {first_name:xxx, last_name:yyy, 1234} 这样的 json 对象,所以我将 true 推送到 loginStatus 并将“傻瓜”返回给进一步的操作员。

我想我会在 loginStatus$ 的点击运算符中得到傻瓜,但事实并非如此。

isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: true
tap: true
tap: true
tap: true

我只得到了第一个 isLoggedIn 请求的响应,其他 3 个丢失了。而且我永远不会傻瓜,我猜所有的异步管道都从 loginStatus BehaviorSubject 得到了真实的。

然后我在 isLoggedIn 函数中注释了 this.loginStatus.next(true) 来比较结果。

isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool
isLogedIn res: {"logined":true,"first_name":"xxx","last_name":"yyy","tel":"1234"}
tap: fool

这是我更喜欢的结果,我打了 4 次电话,所以我得到了 4 个回复,它把傻瓜传给了水龙头 4 次。

我想知道为什么在第一次订阅过程中更改 BehaviorSubject 时会丢失其他响应。
以及为什么所有 4 订阅都能获得真正的价值,我想至少第一次会得到傻瓜。
这是否意味着 BehaviorSubject 将在更改时取消进一步的过程而不是完成它?

标签: angularrxjsbehaviorsubject

解决方案


发生这种情况是因为您正在使用switchMap,这将取消以前的内部可观察对象并处理新的。

BehaviorSubject因此,当您在using中发出值时this.loginStatus.next(true)switchMap运算符将取消先前的 observable 并处理新值(这是真的)。

如果你想实现你的场景,你应该保持之前的内部 observable 正常完成,那么你需要使用mergeMaporconcatMap运算符。


推荐阅读