1

我有 2 个从 Firebase 返回数据的可观察对象,无论我使用哪种类型的组合运算符(forkJoin、CombineLatest 等),异步管道都不会接收数据。

我有一个 AuthService,它有一个从 Firebase 实时数据库初始化用户的方法:

  private initUser(firebaseUser: firebase.User) {
    const myUser: User = {account: {}, profile: {}};
    const userId = `US_${firebaseUser.uid}`;

    const accountSnapshot: Observable<UserAccount> = this.db
      .object(`/users/accounts/${userId}`)
      .valueChanges()
      .pipe(first()) as Observable<UserAccount>;

    const profileSnapshot: Observable<UserProfile> = this.db
      .object(`/users/profiles/${userId}`)
      .valueChanges()
      .pipe(first()) as Observable<UserProfile>;

    forkJoin([accountSnapshot, profileSnapshot])
      .subscribe((result: [UserAccount, UserProfile]) => {
        if (result) {
          myUser.account = result[0];
          myUser.profile = result[1];
          this.setCurrentUser(myUser);
        }
      });
  }

CurrentUser 设置为带有 getter/setter 的主题:

  private currentUser = new Subject<User>();

  public get getCurrentUser(): Observable<User> {
    return this.currentUser.asObservable();
  }

  public setCurrentUser(user: User): void {
    this.currentUser.next(user);
  }

在消费组件中:

  currentUser$: Observable<User>;
  user: User;


  ngOnInit(): void {
    this.currentUser$ = this.authService.getCurrentUser;
    this.currentUser$.subscribe(user => {
      this.user = user;
    });
  }

并在模板中:

<p>Email: {{ ((currentUser$ | async)?.account).email }}</p>. <- ** DOES NOT WORK **
<p>Email: {{ (user?.account).email }}</p> <- ** DOES WORK **

现在,这是奇怪的部分。如果我将initUser方法更改为不合并来自 firebase 的 observables,而是单独获取它们(并将用户配置文件和帐户设置为单独的操作),那么就async可以了。像这样:

accountSnapshot.subscribe((account: UserAccount) => {
  if (account) {
    myUser.account = account;
    this.setCurrentUser(myUser);
  }
});
profileSnapshot.subscribe((profile: UserProfile) => {
  if (profile) {
    myUser.profile = profile;
    this.setCurrentUser(myUser);
  }
});

然后异步管道工作。

我尝试将forkJointoCombineLatestzip. 我也试过移除,pipe(first())async管道从来没有工作过。

为什么是这样?

异步或我的代码有什么问题,或者我对异步如何工作的理解......?

4

2 回答 2

1

这是因为Subject在你的视野准备好之前的火灾。您应该将其更改为 aReplaySubject以便在订阅时重播最新值。

private currentUser = new ReplaySubject<User>(1);

(不在问题范围内)

除此之外,subscribe像在initUser. 对我来说,您可以将代码简化为以下内容:

private readonly initUser$ = new Subject<firebase.User>();

readonly currentUser$: Observable<User> = this.initUser$.pipe(
  map((user) => `US_${user.uid}`),
  switchMap((userId) => combineLatest([
    this.db.object<UserAccount>(`/users/accounts/${userId}`).valueChanges(),
    this.db.object<UserProfile>(`/users/profiles/${userId}`).valueChanges()
  ])),
  map(([ account, profile ]) => ({ account, profile } as User)),
  shareReplay(1)
);

private initUser(firebaseUser: firebase.User) {
  this.initUser$.next(firebaseUser);
}

然后,在您的消费组件中,您可以使用currentUser$可观察的服务来获取用户详细信息

于 2020-06-01T11:41:18.617 回答
0

它不起作用,因为您已经订阅了该 forkjoin :-

将其更改为:-

this.currentUser$ = forkJoin([accountSnapshot, profileSnapshot])
      .pipe(map((result: [UserAccount, UserProfile]) => {
        if (result) {
          myUser.account = result[0];
          myUser.profile = result[1];
          this.setCurrentUser(myUser);
        }
      }));

然后在您的模板中将此 currentUser$ 与 asyncpipe 一起使用。

于 2020-06-01T11:46:19.657 回答