仅运行一次订阅

Sam*_*ath 5 observable rxjs typescript angular google-cloud-firestore

userProfiles$.subscribe(async res => {我只需要运行一次。但它的作用是无限的。你能告诉我如何避免吗?

这是该问题的视频

.ts

async loginWithGoogle(): Promise<void> {
    try {
      const result = await this.afAuth.auth.signInWithPopup(new firebase.auth.GoogleAuthProvider());
      const userId: string = result.additionalUserInfo.profile.id;
      const userProfile: AngularFirestoreDocument<UserProfile> = this.fireStore.doc(`userProfile/${userId}`);
      const userProfiles: AngularFirestoreCollection<UserProfile> = this.fireStore.collection('userProfile/', ref => ref.where('email', '==', result.additionalUserInfo.profile.email));
      const userProfiles$: Observable<UserProfile[]> = userProfiles.valueChanges();

      userProfiles$.subscribe(async res => { //problem is here
        if (res.length == 0) {
          await userProfile.set({
            id: userId,
            email: result.additionalUserInfo.profile.email,
            creationTime: moment().format(),
            lastSignInTime: moment().format()
          });
        } else {
          await userProfile.update({
            lastSignInTime: moment().format()
          });
        }
      });
    }
    catch (err) {
      console.log(err);
    }
  }
Run Code Online (Sandbox Code Playgroud)

我尝试将其转换为promise如下所示。但没有区别。也许我做错了?

 userProfiles$.map(async res => {
        if (res.length == 0) {
          await userProfile.set({
            id: userId, email: result.additionalUserInfo.profile.email,
            creationTime: moment().format(),
            lastSignInTime: moment().format()
          });
        }
      }).toPromise();
Run Code Online (Sandbox Code Playgroud)

版本:

 "typescript": "2.4.2"
 "rxjs": "5.5.2",
Run Code Online (Sandbox Code Playgroud)

Pat*_*dak 5

承诺方式:

userProfiles$.toPromise().then((res) => {
   if (res.length == 0) {
      await userProfile.set({
         id: userId, email: result.additionalUserInfo.profile.email,
         creationTime: moment().format(),
         lastSignInTime: moment().format()
      });
   }
}).catch(err => {
   // handle error
});
Run Code Online (Sandbox Code Playgroud)

首先,将其转换为 Promise,然后通过方法监听它.then()并等待已解决的 Promise。

可观察的.take(1)

userProfiles$.take(1).subscribe(async res => { //problem is here
        if (res.length == 0) {
          await userProfile.set({
            id: userId,
            email: result.additionalUserInfo.profile.email,
            creationTime: moment().format(),
            lastSignInTime: moment().format()
          });
        } else {
          await userProfile.update({
            lastSignInTime: moment().format()
          });
        }
      });
Run Code Online (Sandbox Code Playgroud)

注意方法toPromise不要忘记toPromise从 rxjs 运算符导入,并且您还应该从 rxjstake导入方法take

更新。角度版本 >= 6

从 Angular 6 开始,需要 rxjs >= 6。现在,像这样的运算符take现在可以在方法中导入和使用.pipe()你可以在这里阅读更多

// somewhere at the top of file
import { take } from 'rxjs/operators';

userProfiles$.pipe(take(1)).subscribe(async res => { //problem is here
        if (res.length == 0) {
          await userProfile.set({
            id: userId,
            email: result.additionalUserInfo.profile.email,
            creationTime: moment().format(),
            lastSignInTime: moment().format()
          });
        } else {
          await userProfile.update({
            lastSignInTime: moment().format()
          });
        }
      });
Run Code Online (Sandbox Code Playgroud)


Sam*_*ath -2

我在这里找到了混合使用Angularfire2和 的解决方案firebase native API

我从迈克尔那里得到了这个解决方案。

Firestore 原生 API

get
get() returns firebase.firestore.QuerySnapshot

Executes the query and returns the results as a QuerySnapshot.

Returns
non-null firebase.firestore.QuerySnapshot A promise that will be resolved with the results of the query.
Run Code Online (Sandbox Code Playgroud)

.ts

 constructor() {
     this.db = firebase.firestore();
  }

   async loginWithGoogle(): Promise<string> {
        try {
          const response = await this.afAuth.auth.signInWithRedirect(new firebase.auth.GoogleAuthProvider());
          const result = await this.afAuth.auth.getRedirectResult();
          this.user = result.user;
          const userId: string = result.user.uid;
          const userProfile: AngularFirestoreDocument<UserProfile> = this.fireStore.doc(`userProfile/${userId}`);
          const res = await this.db.collection("userProfiles").where("email", "==", data).get();
          if (res.docs.length === 0) {
            await userProfile.set({
              id: userId,
              email: result.additionalUserInfo.profile.email,
              creationTime: moment().format(),
              lastSignInTime: moment().format()
            });
          } else {
            await userProfile.update({
              lastSignInTime: moment().format()
            });
          }
          return result.additionalUserInfo.profile.email;
        }
        catch (err) {
          console.log(err);
        }
      }
Run Code Online (Sandbox Code Playgroud)