为什么我的异步函数返回Promise {<pending>}而不是值?

时间:2016-08-10 22:24:26

标签: javascript node.js promise

我的代码:

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.username, data.password)获取令牌,将令牌返回到变量中。然后才开始采取行动。

8 个答案:

答案 0 :(得分:96)

只要其结果尚未解决,承诺将始终记录暂挂。无论承诺状态(已解决或仍在等待),您必须在承诺上调用.then来捕获结果:

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方法。

详细

根据Promises / A +规范:

  

承诺解决程序是一个抽象的操作   输入一个promise和一个值,我们将其表示为[[Resolve]](promise,   X)。如果x是一个可怜的,它试图通过承诺采用状态   x,假设x的行为至少有点像a   诺言。否则,它使用值x履行承诺。

     

对theables的这种处理允许承诺实现   互操作,只要它们公开Promise / A + -compliant   方法。它还允许Promises / A +实现“同化”   使用合理的方法进行不一致的实现。

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

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

下面将详细介绍它的实际工作方式:

<强> 1。 .then函数的返回将是promise的已解决值。

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,则该链式承诺的已解析值将传递给以下.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"
  });

答案 1 :(得分:5)

我知道这个问题是2年前问的,但是我遇到了同样的问题,而问题的答案是从ES6开始,您可以简单地await函数返回值,例如:

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

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

答案 2 :(得分:2)

then方法返回一个挂起的promise,它可以通过在then的调用中注册的结果处理程序的返回值异步解析,或者通过在处理程序中抛出一个错误来拒绝。 / p>

因此调用AuthUser不会突然以同步方式记录用户,而是返回一个promise,在登录成功(或失败)后将调用其后注册的处理程序。我建议通过登录promise的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);
}

答案 3 :(得分:0)

请参阅Promises.上的MDN部分。请特别注意then().的返回类型

要登录,用户代理必须向服务器提交请求并等待接收响应。由于在请求往返期间使您的应用程序完全停止执行通常会导致糟糕的用户体验,实际上每个登录您的JS功能(或执行任何其他形式的服务器交互)都将使用Promise,或者非常类似的东西,以异步方式提供结果。

现在,还要注意return语句总是在它们出现的函数的上下文中进行评估。所以当你写下:

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

语句return token;意味着传递给then()的匿名函数应该返回令牌,而不是AuthUser函数应该返回的。 AuthUser返回的是调用google.login(username, password).then(callback);的结果,这恰好是一个承诺。

最终你的回调token => { return token; }什么都不做;相反,您对then()的输入需要是一个以某种方式实际处理令牌的函数。

答案 4 :(得分:0)

您的承诺未完成,请通过以下方式完成

userToken.then(function(result){
console.log(result)
})

在您剩余的代码之后。 这些代码所做的全部工作就是.then()完成您的承诺并在 result 变量中捕获最终结果并在控制台中打印结果。 请记住,您不能将结果存储在全局变量中。 希望解释对您有所帮助。

答案 5 :(得分:0)

我之前也遇到过同样的问题,但是前端的情况有所不同。无论如何,我都会分享自己的情况,也许有人会觉得有用。

我在前端对/api/user/register进行了api调用,并使用电子邮件,密码和用户名作为请求正文。提交表单(注册表单)时,将调用处理程序函数,该函数将启动对/api/user/register的提取调用。我在此处理程序函数的开始行中使用了event.preventDefault(),其他所有行,如形成请求主体,以及在event.preventDefault()之后编写了获取调用。这返回了pending promise

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

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

而不是:

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

答案 6 :(得分:0)

如果这种情况发生在数组等多个值上。

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

您可以使用 Promise.all() 这将解决所有承诺。

<块引用>

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

答案 7 :(得分:-1)

试试这个

var number1 = document.getElementById("number1");
var number2 = document.getElementById("number2");
startAsync.addEventListener("click", function() {
    if (number1.value > 0 && number2.value > 0) {
        asyncTest(parseInt(number1.value), parseInt(number2.value)).then(function(result) {
            document.getElementById("promiseResolved").textContent = "promiseResolved: " + result
        });
    } else {
        asyncTest(1, 2).then(function(result) {
            document.getElementById("promiseResolved").textContent = "promiseResolved: " + result
        });
    }

});

async function asyncTest(a, b) {
    return await (a + b);
};
  <button id="startAsync">start Async function</button><br />
  <input type="number" id="number1" /><br />
  <input type="number" id="number2" /><br />
  <span id="promiseResolved"></span><br />