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"
Why is that?
Promises are forward direction only; You can only resolve them once. The resolved value of a Promise
is passed to its .then
or .catch
methods.
Details
According to the Promises/A+ spec:
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.
This spec is a little hard to parse, so let's break it down. The rule is:
If the function in the .then
handler returns a value, then the Promise
resolves with that value. If the handler returns another Promise
, then the original Promise
resolves with the resolved value of the chained Promise
. The next .then
handler will always contain the resolved value of the chained promise returned in the preceding .then
.
The way it actually works is described below in more detail:
1. The return of the .then
function will be the resolved value of the 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. If the .then
function returns a Promise
, then the resolved value of that chained promise is passed to the following .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"
–
–
–
I ran into the same issue and the answer for the problem is since ES2017, that you can simply await
the functions return value (as of now, only works in async
functions), like:
let AuthUser = function(data) {
return google.login(data.username, data.password)
let userToken = await AuthUser(data)
console.log(userToken) // your data
–
–
–
–
The then
method returns a pending promise which can be resolved asynchronously by the return value of a result handler registered in the call to then
, or rejected by throwing an error inside the handler called.
So calling AuthUser
will not suddenly log the user in synchronously, but returns a promise whose then registered handlers will be called after the login succeeds ( or fails). I would suggest triggering all login processing by a then
clause of the login promise. E.G. using named functions to highlight the sequence of flow:
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);
See the MDN section on Promises. In particular, look at the return type of then().
To log in, the user-agent has to submit a request to the server and wait to receive a response. Since making your application totally stop execution during a request round-trip usually makes for a bad user experience, practically every JS function that logs you in (or performs any other form of server interaction) will use a Promise, or something very much like it, to deliver results asynchronously.
Now, also notice that return
statements are always evaluated in the context of the function they appear in. So when you wrote:
let AuthUser = data => {
return google
.login(data.username, data.password)
.then( token => {
return token;
the statement return token;
meant that the anonymous function being passed into then()
should return the token, not that the AuthUser
function should. What AuthUser
returns is the result of calling google.login(username, password).then(callback);
, which happens to be a Promise.
Ultimately your callback token => { return token; }
does nothing; instead, your input to then()
needs to be a function that actually handles the token in some way.
–
–
–
–
–
after your remaining code.
All this code does is that .then()
completes your promise & captures the end result in result variable & print result in console.
Keep in mind, you cannot store the result in global variable.
Hope that explanation might help you.
–
I had the same issue earlier, but my situation was a bit different in the front-end. I'll share my scenario anyway, maybe someone might find it useful.
I had an api call to /api/user/register
in the frontend with email, password and username as request body. On submitting the form(register form), a handler function is called which initiates the fetch call to /api/user/register
. I used the event.preventDefault()
in the beginning line of this handler function, all other lines,like forming the request body as well the fetch call was written after the event.preventDefault()
. This returned a pending promise
.
But when I put the request body formation code above the event.preventDefault()
, it returned the real promise. Like this:
event.preventDefault();
const data = {
'email': email,
'password': password
fetch(...)
instead of :
const data = {
'email': email,
'password': password
event.preventDefault();
fetch(...)
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 />
–
–