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

时间:2017-02-23 17:07:53

标签: angular rxjs angular2-observables

我想为用户对象创建一个被动商店。所以让我先描述一下我的尝试。我定义了一个简单的用户类:

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

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

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()首先获取用户标识并查询特定用户的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是否会创建某种其他订阅并取消第一个订阅?

1 个答案:

答案 0 :(得分:3)

问题是您的BehaviorSubject正在发出至少两个不同的值

  • null - 实例化主题时提供的初始值。
  • User instance - Firebase调用返回后立即发出的值。
  • [可选]修改后的User实例 - 由于所有内容都与Firebase“实时”关联,因此您的主题可能会继续为当前用户发出不同的实例(例如,如果用户登录,您将获得新值出)。

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

我会尝试使用ReplaySubject。 ReplaySubject 仅在将值明确推送到其中时才开始发送。这意味着您可以删除初始null值,只要Firebase未返回,用户将无法使用(=订阅将“等待”)。

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

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