您可以直接使用.then调用异步函数/方法吗?

时间:2019-05-13 21:31:16

标签: javascript firebase asynchronous promise

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

但是,当我尝试使用.then方法进行操作时,在控制台登录User类的signIn方法之前,app.js文件中的console.log显示为未定义。但是,用户类的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();
            })
        });

1 个答案:

答案 0 :(得分:2)

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

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

signIn

要解决此问题,如果您想在其外部使用signIn() { auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => { console.log(cred); return cred; }); return Promise.resolve(undefined); } ,则需要从async删除signIn关键字,并从signIn返回promise。例如:

.then

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

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; } 诺言完成之前解决。也就是说,您原来的事件处理程序等效于:

signIn

这可能 对您没有任何意义,因为DOM事件要么不在乎回调的返回值,要么在乎诺言。在某些情况下,这一区别可能很重要(例如,如果您在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); } 内/在e.preventDefault()之后调用.then,将无法正常工作