我在这里有一些代码,使用firebase auth将用户登录到firebase。我在我的app.js文件中实例化一个新用户,在该对象上调用signIn方法,然后在用户类的signIn方法中,我通过控制台登录从firebase auth返回的凭据。我还将凭证返回给调用它的对象,并再次控制台记录凭证。当我使用async / await时,代码将按预期运行:它将凭据首先登录到signIn方法中,然后在我调用signIn之后再次将其记录在app.js中。

但是,当我尝试使用.then方法进行操作时,我的app.js文件中的console.log在控制台登录User类的signIn方法之前显示为undefined。但是,User类的signIn方法中的控制台日志返回正确的凭据。

我的问题是:为什么控制台记录之前,我的app.js文件中的控制台日志不等待获取凭证?或者至少是控制台记录了诺言?

   class User {
        constructor(email, password){
            this.email = email;
            this.password = password;
            this.cred;
        }

        async signUp(){
            const cred = await auth.createUserWithEmailAndPassword(this.email, this.password);
            return cred;
        }

        async signIn() {

            auth.signInWithEmailAndPassword(this.email,this.password).then(cred=>{
                console.log(cred);
                return cred;
            });

            //this async/await code below works as expected
            // const cred = await auth.signInWithEmailAndPassword(this.email,this.password);
            // console.log(cred);
            // return cred;
        }

        signOut(){

        }
    }

    export default User


   // beginning of my app.js file

   loginForm && loginForm.addEventListener('submit', async e => {
        e.preventDefault();

        const user = new User(loginForm.email.value,loginForm.password.value);

        //const cred = await user.signIn(); // this async/await code works fine
        //console.log(cred);

            user.signIn().then(cred => {
              console.log(cred); // this console.log fires before the console.log in signIn() and returns undefined
              loginForm.reset();
            })
        });

最佳答案

首先,您应该注意,async / await基本上只是表示基于Promise的工作流的另一种方法。当您将一个函数标记为异步时,基本上是说该函数将返回一个Promise,而当您在一个异步函数中使用await时,则基本上是说该函数的其余部分将成为.then回调的一部分。隐含的承诺。

对于您的问题,signIn()被标记为异步,这意味着它返回一个承诺(这就是为什么signIn().then不会引发TypeError的原因),并且在其中创建了一个承诺(auth.signInWithEmailAndPassword),但是promise不与signIn的隐式Promise绑定,因此隐式Promise立即解决。换句话说,您的signIn原始版本等效于:

signIn() {
  auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => {
    console.log(cred);
    return cred;
  });
  return Promise.resolve(undefined);
}


若要解决此问题,如果要在async之外使用signIn,则需要从signIn删除.then关键字,并从signIn返回诺言。例如:

signIn() {
  return auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => {
    console.log(cred);
    return cred;
  });
}


实际上,以上代码等效于以下异步/等待版本:

async signIn() {
  const cred = await auth.signInWithEmailAndPassword(this.email,this.password);
  console.log(cred);
  return cred;
}


请注意,尽管在事件侦听器中,您不是在等待诺言,所以它会在e.preventDefault()诺言完成之前解决。也就是说,您原始的事件处理程序等效于:

e => {
  e.preventDefault();

  const user = new User(loginForm.email.value,loginForm.password.value);
  user.signIn().then(cred => {
    console.log(cred);
    loginForm.reset();
  });
  return Promise.resolve(undefined);
}


这可能对您没有任何意义,因为DOM事件要么不在乎回调的返回值,要么在乎诺言。这是在某些情况下可能很重要的区别(例如,如果在.then内/之后在async之后调用,则将不起作用)

关于javascript - 您可以直接使用.then调用异步函数/方法吗?,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/56120119/

10-12 15:29