I'm currently struggling with returning a value from a chained event resulting in a Promise returned in a pending state.
My code returns an array of metafield objects for a specific Shopify product, which I then parse and would like to return an integer value.
However when I debug my code all I'm getting is a promise in a pending state rather than an executed value which is in scope to use.
I'm guessing this is largely down to my unfamiliarity with promises.
Any help greatly appreciated!
var quantity = shopify.metafield.list({
metafield: { owner_resource: 'product', owner_id: line_item.product_id }
}).then(metafields => new Promise(function(resolve, reject) {
//simplified code
resolve(2);
}))
.catch(error => console.log(error));
shopify.metafield.list({
metafield: { owner_resource: 'product', owner_id: line_item.product_id }
}).then(metafields => new Promise(function(resolve, reject) {
//simplified code
resolve(2);
})).then((quantity)=> console.log(quantity))
.catch(error => console.log(error));
2nd .then() function is returning a new promise so you need to chain .then() function again in order to get the exact value returned from the promise(resolve)
Other way is to just use .then() function on quantity variable which contains promise returned by 2nd .then() function
quantity.then((res)=> console.log(res))
Related
My code:
let AuthUser = data => {
return google.login(data.username, data.password).then(token => { return token } )
}
And when i try to run something like this:
let userToken = AuthUser(data)
console.log(userToken)
I'm getting:
Promise { <pending> }
But why?
My main goal is to get token from google.login(data.username, data.password) which returns a promise, into a variable. And only then preform some actions.
The promise will always log pending as long as its results are not resolved yet. You must call .then on the promise to capture the results regardless of the promise state (resolved or still pending):
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 know this question was asked 2 years ago, but I run 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);
}
If that situation happens for a multiple values like an array.
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
You can use Promise.all() this will resolve all promises.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
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.
Your Promise is pending, complete it by
userToken.then(function(result){
console.log(result)
})
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(...)
...
Try this
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 />
Im my case (JS) I forgot to add await
I am looking to return an array in a promise but it keeps saying promise pending. It is returning promise: fulfilled and promise value: array. I have read the documentation and the thread on here about promises and have tried to use it as a function. I have tried to use async await but nothing seems to be working. I read somewhere that you can store it in a global variable, is that the case. Or is you can't store it in a global variable when you use React, because I am using React. Can someone point me in the right direction?
Here's my code:
const currentSymbol = fetch(`https://finnhub.io/api/v1/stock/symbol?exchange=US&token=${key}`)
.then((res) => {
return res.json();
}).then((results) => {
return results.map(result => {
return result
})
})
console.log(currentSymbol)
How about this beautiful await / async implementation ?
function currentSymbol(){
return new Promise(function(resolve){
fetch(`https://finnhub.io/api/v1/stock/symbol?exchange=US&token=${key}`)
.then((res) => {
resolve( res.json());
})
});
}
Then get result with:
let result = await currentSymbol();
The issue is that you are logging a Promise object which is awaitable. To execute the Promise and get its actual result you need to make use of either .then() or await implementation on the Promise object itself
Actually, I don't know how to check this on real Promise super class, so I'm testing it with a class extending it. But it seems to me the result would be the same.
class PromisePlus extends Promise {
constructor (handler) {
super(handler)
console.log('new promise created')
}
}
new PromisePlus((resolve, reject) => {
resolve()
}).then(() => {
return 'GOOD'
}).then(msg => {
console.log(msg)
})
prints 'new promise created' 3 times
new PromisePlus((resolve, reject) => {
resolve()
}).then(() => {
return PromisePlus.resolve('BAD')
}).then(msg => {
console.log(msg)
})
prints 'new promise created' 5 times.
The same result with returning new Promise inside then handler
new PromisePlus((resolve, reject) => {
resolve()
}).then(() => {
return new PromisePlus((resolve, reject) => {
resolve('BAD')
})
}).then(msg => {
console.log(msg)
})
Obviously, PromisePlus.resolve() creates new promise, but why does returning PromisePlus.resolve() inside then cause one more extra promise creation?
Why does returning PromisePlus.resolve() inside then cause one more extra promise creation?
Because when you are returning a promise from a then callback, it does get awaited to resolve the outer promise (the one returned from .then()). To await this inner promise, .then(…) gets called on it - and this call does create a new promise as well.
(Yes, all this is horribly inefficient, which is probably the #1 reason why promise subclassing should be avoided).
My code:
let AuthUser = data => {
return google.login(data.username, data.password).then(token => { return token } )
}
And when i try to run something like this:
let userToken = AuthUser(data)
console.log(userToken)
I'm getting:
Promise { <pending> }
But why?
My main goal is to get token from google.login(data.username, data.password) which returns a promise, into a variable. And only then preform some actions.
The promise will always log pending as long as its results are not resolved yet. You must call .then on the promise to capture the results regardless of the promise state (resolved or still pending):
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 know this question was asked 2 years ago, but I run 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);
}
If that situation happens for a multiple values like an array.
[
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> },
Promise { <pending> }
]
You can use Promise.all() this will resolve all promises.
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise/all
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.
Your Promise is pending, complete it by
userToken.then(function(result){
console.log(result)
})
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(...)
...
Try this
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 />
Im my case (JS) I forgot to add await
'use strict';
Promise.resolve(() => 'John')
.then((args) => {
console.log(args);
throw new Error('ops')
})
.catch((ex) => {
console.log(ex)
})
.then(() => {
throw new Error('ups')
console.log('Doe')
})
I think console.log(args); should output 'John', but when I run this code, the output is [ [Function] ]
So I am confused.
Promise.resolve will create a new Promise resolved with the value you pass to it. So, in your case, your promise is actually resolved with the function object. It means that, the then handler is passed the function object itself.
What you should have done is
new Promise((resolve, reject) => resolve('John'))
.then(args => {
console.log(args);
throw new Error('ops')
})
.catch(console.log.bind(console));
Now, you are creating a Promise object and you are resolving that with the value John.
If you want your Promise to be resolved with a value readily, then don't pass the function object but pass the actual value itself to Promise.resolve function.
Promise.resolve('John')
.then(args => {
console.log(args);
throw new Error('ops')
})
.catch(console.log.bind(console));
Now, you have a Promise, resolved with value John and the then handler will get the resolved value John.
Note: This is the recommended way of creating a Promise when you know the actual way to resolve with readily, so that you can avoid the Promise constructor anti-pattern.
'use strict';
Promise.resolve('John')
.then((args) => {
console.log(args);
throw new Error('ops')
})
.catch((ex) => {
console.log(ex)
})
.then(() => {
throw new Error('ups')
console.log('Doe')
})
I modify Promise.resolve('John'), it works.
Please see the Promise.resolve.
resolve is used to pass the arguments directly to the then-handler
if you want 'John', you need to call the anonymous function in your call to resolve()
Promise.resolve(function(){return 'John';}());
notice the }() function call.