我的代码:

let AuthUser = data => {
  return google.login(data.username, data.password).then(token => { return token } )
}

当我试图运行这样的东西:

let userToken = AuthUser(data)
console.log(userToken)

我得到:

Promise { <pending> }

但是为什么呢?

我的主要目标是得到令牌从google.login(数据。用户名,data.password),返回一个承诺,到一个变量。然后再执行一些动作。


当前回答

只要promise的结果还没有被解决,它就总是记录挂起的日志。你必须在promise上调用.then来捕获结果,而不管promise状态是什么(已解决或仍在等待):

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }

userToken.then(function(result) {
   console.log(result) // "Some User token"
})

为什么呢?

承诺只是前进的方向;你只能解决一次。Promise的解析值被传递给它的.then或.catch方法。

细节

根据承诺/A+规范:

The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x. This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.

这个规范有点难以解析,所以让我们详细分析一下。规则是:

如果.then处理程序中的函数返回一个值,则Promise解析该值。如果处理程序返回另一个Promise,则原始Promise将使用链接的Promise的已解析值进行解析。下一个.then处理程序将始终包含在前一个.then中返回的链式承诺的解析值。

它的实际工作方式如下所述:

1. then函数的返回值将是承诺的解析值。

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return "normalReturn";
  })
  .then(function(result) {
    console.log(result); // "normalReturn"
  });

2. 如果.then函数返回一个Promise,则该链接Promise的解析值将传递给下面的.then。

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return new Promise(function(resolve, reject) {
       setTimeout(function() {
          resolve("secondPromise");
       }, 1000)
    })
  })
  .then(function(result) {
    console.log(result); // "secondPromise"
  });

其他回答

我知道这个问题2年前就被问过了,但我遇到了同样的问题,问题的答案是自ES2017以来,你可以简单地等待函数的返回值(截至目前,只适用于异步函数),比如:

let AuthUser = function(data) {
  return google.login(data.username, data.password)
}

let userToken = await AuthUser(data)
console.log(userToken) // your data

我之前也遇到过同样的问题,但我在前端的情况有点不同。我还是会分享我的场景,也许有人会觉得有用。

我有一个api调用/api/user/注册在前端的电子邮件,密码和用户名作为请求体。在提交表单(注册表单)时,会调用一个handler函数,它会启动对/api/user/register的取回调用。我在这个处理函数的开始行中使用了event.preventDefault(),所有其他行,比如形成请求体以及获取调用都是在event.preventDefault()之后编写的。这将返回一个待处理的承诺。

但是当我把请求正文的形成代码放在event.preventDefault()上面时,它返回了真正的承诺。是这样的:

event.preventDefault();
    const data = {
        'email': email,
        'password': password
    }
    fetch(...)
     ...

而不是:

     const data = {
            'email': email,
            'password': password
        }
     event.preventDefault();
     fetch(...)
     ...

只要promise的结果还没有被解决,它就总是记录挂起的日志。你必须在promise上调用.then来捕获结果,而不管promise状态是什么(已解决或仍在等待):

let AuthUser = function(data) {
  return google.login(data.username, data.password).then(token => { return token } )
}

let userToken = AuthUser(data)
console.log(userToken) // Promise { <pending> }

userToken.then(function(result) {
   console.log(result) // "Some User token"
})

为什么呢?

承诺只是前进的方向;你只能解决一次。Promise的解析值被传递给它的.then或.catch方法。

细节

根据承诺/A+规范:

The promise resolution procedure is an abstract operation taking as input a promise and a value, which we denote as [[Resolve]](promise, x). If x is a thenable, it attempts to make promise adopt the state of x, under the assumption that x behaves at least somewhat like a promise. Otherwise, it fulfills promise with the value x. This treatment of thenables allows promise implementations to interoperate, as long as they expose a Promises/A+-compliant then method. It also allows Promises/A+ implementations to “assimilate” nonconformant implementations with reasonable then methods.

这个规范有点难以解析,所以让我们详细分析一下。规则是:

如果.then处理程序中的函数返回一个值,则Promise解析该值。如果处理程序返回另一个Promise,则原始Promise将使用链接的Promise的已解析值进行解析。下一个.then处理程序将始终包含在前一个.then中返回的链式承诺的解析值。

它的实际工作方式如下所述:

1. then函数的返回值将是承诺的解析值。

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return "normalReturn";
  })
  .then(function(result) {
    console.log(result); // "normalReturn"
  });

2. 如果.then函数返回一个Promise,则该链接Promise的解析值将传递给下面的.then。

function initPromise() {
  return new Promise(function(res, rej) {
    res("initResolve");
  })
}

initPromise()
  .then(function(result) {
    console.log(result); // "initResolve"
    return new Promise(function(resolve, reject) {
       setTimeout(function() {
          resolve("secondPromise");
       }, 1000)
    })
  })
  .then(function(result) {
    console.log(result); // "secondPromise"
  });

如果这种情况发生在一个多值的数组中。

[ 
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> },
  Promise { <pending> }
]

你可以使用Promise.all()来解决所有的promise。

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all

then方法返回一个挂起的承诺,该承诺可以通过在then调用中注册的结果处理程序的返回值异步解析,也可以通过在被调用的处理程序中抛出错误来拒绝。

因此,调用AuthUser不会突然同步地让用户登录,而是返回一个承诺,在登录成功(或失败)后调用该承诺的注册处理程序。我建议通过登录承诺的then子句触发所有登录处理。例如,使用命名函数来突出显示流的顺序:

let AuthUser = data => {   // just the login promise
  return google.login(data.username, data.password);
};

AuthUser(data).then( processLogin).catch(loginFail);

function processLogin( token) {
      // do logged in stuff:
      // enable, initiate, or do things after login
}
function loginFail( err) {
      console.log("login failed: " + err);
}