简体   繁体   中英

How to get signInAnonymously from AngularFireAuth to return a promise

I've been following fireship.io's tutorial for setting up stripe payments. In their repo's auth service , I'm seeing a lot of conversions of observables to promises, presumably to allow for the very useful and readable async/await syntax in the checkout component. For instance, this method exists in the auth service:

getUser(): Promise<any> {
    return this.afAuth.authState.pipe(first()).toPromise();
  }

allowing for a call like this in the component

const user = await this.auth.getUser();

I'm trying to essentially allow users to make a donation to my webapp, which doesn't require any login whatsoever. Currently, I have a call to stripeCreateCharge in my checkout component (see below), but it depends on the auth.getUser() method, which I think means I need some kind of login.

So, I created an anonymous login method in the auth service, and call it upstream of the handler call.

From auth.service.ts:

anonymousLogin() {
    console.log("anonymousLogin entered");
    // console.log('AuthIsStateResolved: ' + this.afAuth.auth.isStateResolved_);
    this.afAuth.auth.signInAnonymously()
     .then((credential) => {
       console.log("success inside callback for signInAnonymously");
       console.log(credential.user);
       // this.authState = credential;
       this.updateUserData(credential.user);
       return this.getUser();
     })
     .catch(error => console.log(error));
  }

In my checkout.component.ts:

ngOnInit() {
    this.auth.signOut();
    this.handler = StripeCheckout.configure({
      key: 'pk_live_ztqhLfPwjEf2SFC26LDmWkXr',
      locale: 'auto',
      source: async (source) => {
        this.displayThings = true;
        this.loading = true;
        console.log("got into source callback from handler in checkout.component");
        this.auth.anonymousLogin();
        const user = await this.auth.getUser();
        console.log(user);
        if(user){
          const fun = this.functions.httpsCallable('stripeCreateCharge');
          this.confirmation = await fun({ source: source.id, uid: user.uid, amount: this.amount }).toPromise();
          console.log("this.confirmation");
          console.log(this.confirmation.outcome.seller_message);
          this.loading = false;
          if(this.confirmation.outcome.seller_message === "Payment complete."){
            this.paymentStatus = this.confirmation.outcome.seller_message + " Thank you!";
          } else{
            this.paymentStatus = this.confirmation.outcome.seller_message;
          }
        } else{
          console.log("ack never happened");
        }
      }
    });
  }

Paying special attention to the lines

        this.auth.anonymousLogin();
        const user = await this.auth.getUser();
        console.log(user);

above, I'm seeing that this.auth.anonymousLogin() doesn't complete until after const user = await this.auth.getUser(); gets called, so we have an asynchronicity issue, as evidenced by the console output:

在此处输入图像描述

My question: is there a way I can modify anonymousLogin() to return a promise when it's done, so that I can continue using the async/await syntax, and have something like,

        const loggedInStatus = await this.auth.anonymousLogin();
        if(loggedInStatus){
            const user = await this.auth.getUser();
            console.log(user);
            // More stuff in here...
        }

Alternatively, is there better advice for how to handle this whole thing?

Update 17 December, 2019:

When I add return to my signInAnonymously method, it returns undefined in my checkout.component.ts:

auth.service.ts

...
anonymousLogin() {
    console.log("anonymousLogin entered");
    // console.log('AuthIsStateResolved: ' + this.afAuth.auth.isStateResolved_);
    return this.afAuth.auth.signInAnonymously()
     .then((credential) => {
       console.log("success inside callback for signInAnonymously");
       console.log(credential.user);
       // this.authState = credential;
       this.updateUserData(credential.user);
       // return this.getUser();
     })
     .catch(error => console.log(error));
  }

checkout.component.ts

...
const loggedInStatus = await this.auth.anonymousLogin();
        console.log("test user");
        console.log(loggedInStatus);
        const user = await this.auth.getUser();
        console.log(loggedInStatus);
        //below not updated yet
        if(user){
          const fun = this.functions.httpsCallable('stripeCreateCharge');
          this.confirmation = await fun({ source: source.id, uid: user.uid, amount: this.amount }).toPromise();
          console.log("this.confirmation");
          console.log(this.confirmation.outcome.seller_message);
          this.loading = false;
          if(this.confirmation.outcome.seller_message === "Payment complete."){
            this.paymentStatus = this.confirmation.outcome.seller_message + " Thank you!";
          } else{
            this.paymentStatus = this.confirmation.outcome.seller_message;
          }
        } else{
          console.log("ack never happened");
        }
...

在此处输入图像描述

In order to create a proper Promise chain you need to:

  • return a Promise

  • pass the result through the chain of.then handlers

So your code should be like:

anonymousLogin() {
    return this.afAuth.auth.signInAnonymously()
    ^^^^^^
   add this

     .then((credential) => {
       return this.getUser();
      ^^^^^^
 return smth in then callback
     })
     ...
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM