可观察数据服务,订阅不调用

Observable data service, subscribe not called

我想为用户对象创建一个响应式存储。因此,让我首先描述一下我尝试过的内容。我定义了一个简单的用户 class:

export class User {
  constructor(public $key: string) {}
}

为简单起见,class 只包含一个密钥。我使用 firebase 存储并查询此存储我创建了一个服务 class:

export class UserService {

  constructor(private af: AngularFire, private authService: AuthService) {}

  getUser() {
    return this.authService.authInfo$.concatMap(a => this.af.database.object('/users/' + a.uid));
  }
}

getUser() 首先获取用户 ID 并查询特定用户的 firebase 数据库。但是我不想直接使用该服务。相反,我希望有一个具有 BehaviorSubject 的全局存储,其中包含最新的用户对象。那么让我们介绍一下商店:

export class UserStore {

  private _user: BehaviorSubject<User> = new BehaviorSubject(null);

  constructor(private userService: UserService) {
    this.userService.getUser().subscribe(
      userJson => {
        this._user.next(new User(userJson.$key, userJson.firstName, userJson.lastName, null, userJson.personalDataSheet));
      },
      err => console.error
    );
  }

  get user() {
    return this._user.asObservable();
  }
}

现在我在这样的组件中使用这个商店:

this.userStore.user.subscribe(
  user => console.log(user)
);

而且有效!用户已登录。但是当我做类似

的事情时
user: User;
...
this.userStore.user.subscribe(
  user => this.user = user
);

subscribe 只会在用户为空的情况下被调用一次。这是为什么? this.user = user 是否创建了另一种订阅并取消了第一个订阅?

问题是 至少有两个不同的值 被你的 BehaviorSubject 发出:

  • null — 您在实例化主题时提供的初始值。
  • User 实例——当 Firebase 调用 returns.
  • 时发出的值
  • [可选] 修改后的 User 实例 — 由于 Firebase 的一切都是 "live",您的主题可能会继续为当前用户发出不同的实例(例如,您将获得一个新值如果用户注销)。

因此,根据 .subscribe() 的执行点,您最终可能会得到 null 值。

我会尝试改用 ReplaySubject。 ReplaySubject 只有在明确将值推入其中后才开始发射。这意味着您可以摆脱初始 null 值,只要 Firebase 没有返回,用户就不会可用(= 订阅将是 "waiting")。

更具体地说,这是我要更改的行:

private _user: ReplaySubject<User> = new ReplaySubject<User>(1);