如何避免 return promise 中的 observable

How to avoid to return an observable inside a promise

我正在使用 AngularFire 在我的应用程序中管理用户。我仍在学习 observables 和 rxjs。

我正在尝试调用 signInWithEmailAndPassword 方法 - return 一个承诺 - 并从集合中检索文档。

在我的服务中,我使用此方法获取文档:

getDbUser(uid): Observable<User> {
   return this.angularFirestore.collection<User>(USERS).doc(uid).valueChanges()
}

我用以下方式登录用户:

login(user: User) {

    // sign in con email e password
    return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
      .then((result) => {

        if(result.user?.uid) {
        
          // get user doc
          return this.getDbUser(result.user.uid);
        }

        return null;
      });

  }

使用此代码,调用登录方法需要解决一个承诺,然后订阅可观察对象,如下所示:

this.userService.login(this.loginUser)
  .then((userObs) => {
      userObs.subscribe((user) => {
        console.log(user);
      });
  })

我真的很想避免这种情况,但我不知道该怎么做。我尝试使用 RxJs toPromise operator:

login(user: User) {

    // sign in con email e password
    return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
      .then((result) => {

        if(result.user?.uid) {

          // recupero l'utente dal db
          return this.getDbUser(result.user.uid).toPromise();
        }

        return null;
      });

  }

但不知何故这是行不通的(承诺从未得到解决)。

如果你想让任何可观察的消费者知道用户只是在 signInWithEmailAndPassword() 返回后才登录,我会标示一个主题并从任何服务消费者订阅 user$。

private userSubject$:Subject<string>=new Subject<string>();
public user$:Observable<string>=this.userSubject$.asObservable();
    login(user: User) {

    // sign in con email e password
    return this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)
      .then((result) => {

        if(result.user?.uid) {

          // recupero l'utente dal db
          return this.userSubject$.next(result.user.uid);
        }

        return null;
      });

} 从外部您将使用该服务:

this.userService.login(this.loginUser);
this.userService.user$.subscribe(user=>console.log);

第一条评论为正确答案:

You can add .pipe(first()) before .toPromise"

toPromise() 不起作用的原因是 observable 保持打开状态。使用 first 运算符,或者如果您使用的是更高版本的 rxjs,则使用 firstValueFrom。在 Conversion to Promises 从 rxjs 文档中阅读更多相关信息。

由于您使用的是 valuesChanges 而不是 get,那么您的意图可能是保持 observable 打开。如果是这种情况,那么最好的办法是使用 from.

将登录名转换为可观察的
login(user: User) {
  return from(this.angularFireAuth.signInWithEmailAndPassword(user.email, user.password)).pipe(
    switchMap(res => (res.user.uid) 
      ? this.getDbuser(res.user.uid)
      : of(null))
  );
}