Javascript 你能直接用.调用异步函数/方法吗?

Javascript 你能直接用.调用异步函数/方法吗?,javascript,firebase,asynchronous,promise,Javascript,Firebase,Asynchronous,Promise,这里有一些代码,我使用firebase auth将用户登录到firebase。我在app.js文件中实例化一个新用户,调用该对象上的signIn方法,然后在user类的signIn方法中,我在控制台上记录firebase auth的返回凭证。我还将凭证返回给调用它的对象,并再次记录凭证。当我使用async/await时,代码运行与我预期的一样:它首先将凭证记录在signIn方法中,然后在我调用signIn之后再次记录在app.js中 但是,当我尝试使用.then方法时,我的app.js文件中的c

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

但是,当我尝试使用.then方法时,我的app.js文件中的console.log在User类的sign方法中的console log之前显示为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时,基本上是说这个函数将返回一个承诺,而当您在一个async函数中使用Wait时,基本上是说这个函数的其余部分将是
的一部分。然后
回调该隐式承诺

说到你的问题,
signIn()
被标记为异步,这意味着它返回一个承诺(这就是为什么
signIn()。然后
不会抛出一个TypeError),在它里面你创建了一个承诺(
auth.signInWithEmailAndPassword
),但是这个承诺与
signIn
的隐含承诺没有联系,因此,隐含的承诺会立即得到解决。换句话说,您的
登录的原始版本相当于:

signIn() {
  auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => {
    console.log(cred);
    return cred;
  });
  return Promise.resolve(undefined);
}
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);
}
若要修复此行为,需要从
signIn
中删除
async
关键字,并从
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;
}
请注意,在事件侦听器中,您并不是在等待承诺,因此它将在
signIn
承诺完成之前解决。也就是说,您的原始事件处理程序相当于:

signIn() {
  auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => {
    console.log(cred);
    return cred;
  });
  return Promise.resolve(undefined);
}
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事件或者不关心回调的返回值,或者不尊重承诺。这一区别在某些情况下可能很重要(例如,
e.preventDefault()
如果在
中调用它,它将不起作用。然后,
/在
异步
之后)

首先,您应该注意,/功能本质上只是表达基于承诺的工作流的另一种方式。当您将一个函数标记为async时,基本上是说这个函数将返回一个承诺,而当您在一个async函数中使用Wait时,基本上是说这个函数的其余部分将是
的一部分。然后
回调该隐式承诺

说到你的问题,
signIn()
被标记为异步,这意味着它返回一个承诺(这就是为什么
signIn()。然后
不会抛出一个TypeError),在它里面你创建了一个承诺(
auth.signInWithEmailAndPassword
),但是这个承诺与
signIn
的隐含承诺没有联系,因此,隐含的承诺会立即得到解决。换句话说,您的
登录的原始版本相当于:

signIn() {
  auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => {
    console.log(cred);
    return cred;
  });
  return Promise.resolve(undefined);
}
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);
}
若要修复此行为,需要从
signIn
中删除
async
关键字,并从
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;
}
请注意,在事件侦听器中,您并不是在等待承诺,因此它将在
signIn
承诺完成之前解决。也就是说,您的原始事件处理程序相当于:

signIn() {
  auth.signInWithEmailAndPassword(this.email,this.password).then((cred) => {
    console.log(cred);
    return cred;
  });
  return Promise.resolve(undefined);
}
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事件或者不关心回调的返回值,或者不尊重承诺。这一区别在某些情况下可能很重要(例如,
e.preventDefault()
如果在
内部调用它,则它将不起作用。然后在
异步后

您的
登录()
需要在内部返回承诺。当前它不返回任何内容,这就是为什么
user.signIn().then()
根本不应该工作的原因。因为signIn不返回承诺,所以它不是链的一部分。您的
signIn()
需要在内部返回承诺。目前它不返回任何内容,这就是为什么
user.signIn().then()
根本不应该工作的原因。因为signIn不返回承诺,所以它不是链的一部分。太棒了。它现在起作用了,我需要回报这个承诺,这是有道理的。为了确保我完全理解,请注意最后一点“尽管在您的事件侦听器中,您没有等待承诺,因此它将在
签名
承诺完成之前返回。”通过在我的
签名
中返回承诺,我将在我的事件监听器中有效地等待这个承诺?@user2954945我已经更新了我的答案,以提供更完整的解释。真棒的解释!谢谢!我从中学到了很多。太棒了。它现在起作用了,我需要回报这个承诺,这是有道理的。为了确保我完全理解,请注意最后一点“尽管在您的事件侦听器中,您没有等待承诺,因此它将在
签名
承诺完成之前返回。”通过在我的
签名
中返回承诺,我将在我的事件监听器中有效地等待这个承诺?@user2954945我已经更新了我的答案,以提供更完整的解释。真棒的解释!谢谢!我学到了很多