javascript not resolving promise - javascript

Javascript code, trying to resolve a promise immediately:
var promiseData;
var promise = <<<promise maker>>>.then(function (myContent) {
console.log("success");
}, function () {
console.log("fail!");
});
Promise.resolve(promise)
console.log("about to return");
return promiseData;
which output's to the console:
about to return
success
I have a requirement to make the promise return immediately (the promise is being created in a callback method, and the method needs to return a value immediately, returning the data later means we are no longer in the correct context and the value (that has not yet been returned) has already been used (as undefined).
Any suggestions of what I might be doing wrong?
Update:
<<<promise maker>>> is a call to a dependency that returns a promise;

It looks like you expect Promise.resolve(promise) to immediately halt, wait until the promise is resolved, and continue afterwards. That would come close to synchronous execution.
However, Promise.resolve(value) returns a Promise that immediately resolves with value, it does not resolve an existing Promise.
What you're looking for is await (or just Promise.then):
var promise = <<<promise maker>>>.then(function (myContent) {
console.log("success");
}, function () {
console.log("fail!");
});
promise.then(function() {
console.log("about to return");
});
You might observe that I left out the promiseData in the snippet. That's because in order to return the data at the right moment, you have to be asynchronous there as well. So you have to actually return a Promise that will resolve with promiseData, it comes down to:
<<<promise maker>>>
.then(function(promiseData) {
console.log('success');
return promiseData;
})
.then(function(promiseData) {
console.log('about to return');
return promiseData;
})
.catch(function(err) { console.log('fail!'); })

If I am not wrong, this function flow is near what you need, but it also returns a promise resolved into promiseData:
async function getPromiseData() {
try {
const promiseData = await <<<promise maker>>>;
console.log("success");
console.log("about to return");
return promiseData;
} catch (err) {
console.log("fail!");
}
}

Related

Is it possible to cancel a child promise when parent is cancelled?

I have this code (using Bluebird Promise):
const promise = loadSomething(id)
.then(something => {
loadParentOfSomething(something.parentId);
return something;
});
When I then do promise.cancel() the getSomething is cancelled, but the getSomethingParent is not.
Is there a way to, when getSomething promise is cancelled, I can also get the getSomethingParent promise to cancel?
Both load functions returns a cancellable async promise with an HTTP request, and the reason I want to cancel them is because they can sometimes take a while to load and when for example a user navigates away (SPA) the response is no longer needed.
I think what you are actually looking for
const promise1 = loadSomething(id);
const promise2 = promise1.then(something => { return loadParentOfSomething(something.parentId); });
// ^^^^^^
promise2.catch(e => void "ignore"); // prevent unhandled rejections
Then you can keep using promise1 to access the result, but also call promise2.cancel(). This cancellation will be possible even after promise1 settled.
Define a function as the second parameter of the then callback. Example:
const promise = getSomething(id)
.then(something => {
getSomethingParent(something.parentId);
return something;
}, error => {
console.error(error)
});
When you call promise.reject() then getSomethingParent will not be called.
Reference
If you prepare a dummy promise to reference loadSomethingOfParent you should be able to cancel it within loadSomething.
// Create a dummy promise to reference `loadParentOfSomething`
var dummyPromise = Promise.resolve();
// Pass `dummyPromise` to `loadSomething`
const promise = loadSomething(id, dummyPromise).then(something => {
dummyPromise = loadParentOfSomething(something.parentId);
return something;
});
loadSomething will need an onCancel handler which will execute when the promise is cancelled.
function loadSomething(id, promise) {
return new Promise(function(resolve, reject, onCancel) {
// Do your stuff
// The `.cancel()` handler
onCancel(function() {
promise.cancel();
});
});
}

Why i need to resolve a response in promise

I have a promise like below:
let promise = new Promise((resolve, reject) => {
axios.post("https://httpbin.org/post", params, header)
.then(response => {
resolve(Object.assign({}, response.data));
// resolve("aaaa");
console.log(response);
})
.catch(error => reject(error))
});
Why i need to resolve this promise with response data?
What happens if i replace resolve(Object.assign({}, response.data)); line by resolve("aaaa"); ?
Any one can help me? Thank you.
Something that's worth mentioning is axios.post() already returns a Promise so you needn't wrap it in another promise.
This will work instead:
let promise = axios.post("https://httpbin.org/post", params, header)
.then(response => {
console.log(response);
return Object.assign({}, response.data);
});
// Later on...
promise.then(data => {
console.log('Request successful:', data);
}, err => {
console.log('Request failed:', err);
});
Constructing a new Promise object is only necessary when you aren't chaining off an existing promise, like in this example:
function delay(duration) {
return new Promise(resolve => setTimeout(resolve, duration));
}
delay(1000).then(() => {
console.log('this code is delayed by 1s');
});
resolve() does exactly what the name says: It resolves the promise returning the value inside the function call.
So if you have a promise and it is resolving with resolve('aaaaa'), this means your promise will return a successful state with it's value being 'aaaaa'.
You could also reject the promise. This would mean the call you did failed at some point. Analog to resolve(), reject() accepts a parameter that should be returned by the promise.
All it will do is call the success callback resolve with the argument "aaaa" instead of its original value.
Let's say you pass the callback function console.log. If the promise resolves, i.e. is successful, then the callback will be called with the passed argument (console.log("aaaa"))
If it doesn't resolve - if it's unsuccessful - then the reject callback will be called as per your .catch() statement.
Promises have two arguments, resolve and reject, that are used to send a response back to the invoking code.
If your promise completed its code without errors, then you resolve() it, by sending back the response (it can be whatever you want) and if it fails instead, you reject() it, usually passing the error as parameter.
The parameter of the resolve function will be sent back to the invoking function, in the then callback, while the parameter of the reject function can be found in the catch callback.
For example
function myFunction(){
return new Promise((resolve, reject) => {
try{
/* Do some async calls here */
resolve(result); //Result is what you will find in "then"
}catch(e){
reject(e);
}
});
}
myFunction().then((response) => {
/* Your logic here*/
}).catch((err) => {
console.error(err);
}
You can think the resolve as a return in an asynchronous context, while the reject is similar to throwing an exception that will be caught by the invoking code.
So resolve(myVariable) will return myVariable to the code that called the promise function, while resolve('aaa') will always return "aaa" to the invoking code.

Extracting object returned from promise to push to an array, returning as Promise {<pending>} with [[PromiseValue]] object [duplicate]

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

How to Reject Promise in _.each loop

How to reject the promise from the _.each loop, it is never reaching document.write('Failed');. Are there any better functions in lodash to handle this situation.
function check(){
return Promise
.all(
[
Promise.resolve([1,3,4]),
Promise.resolve([0,4,3]),
Promise.resolve(undefined)
]).then(function(results){
return _.each(results, function(result){
return _.each(result, function(value) {
// should reject when value is 0
if(!value){
return Promise.reject();
}
});
});
});
}
check().then(function(){
document.write('All Success');
}, function(){
// Never reaching this code.. :(
document.write('Failed');
});
Here is the plnkr.co link
There's no reason to create a new promise in the then callback and return it. The point of promises is to allow you to write asynchronous code in a more 'synchronous-like' way. What you want to do in your then callback is to throw an error:
function check(){
return Promise
.all(
[
Promise.resolve([1,3,4]),
Promise.resolve([0,4,3]),
Promise.resolve(undefined)
]).then(function(results){
return _.each(results, function(result){
return _.each(result, function(value) {
// should reject when value is 0
if(!value){
throw new Error();
}
});
});
});
}
check().then(function(){
document.write('All Success');
}, function(){
// Never reaching this code.. :(
document.write('Failed');
});
This will cause a rejection in the promise chain.
The _.each() function returns the list in the first parameter and cannot be broken out of, according to the documentation.
To achieve what you want, try using the for...of loop as documented here:
function check(){
return Promise
.all(
[
Promise.resolve([1,3,4]),
Promise.resolve([0,4,3]),
Promise.resolve(undefined)
]).then(function(results){
for (let result of results) {
for (let value of result) {
// should reject when value is 0
if(!value){
return Promise.reject();
}
});
});
});
}
check().then(function(){
document.write('All Success');
}, function(){
// Never reaching this code.. :(
document.write('Failed');
});
If you insist on using the _.each() loop you will never be able to break out of the loop when it hits the first rejection, so I wouldn't recommend that approach. However, you could declare a variable just before the first loop that initially contains a resolved promise, replace it with a rejected promise if the !value check passes and then return this variable after the loop at the end of the final then().
You could use Promise.all again, combined with flatten and map
function check(){
return Promise
.all(
[
Promise.resolve([1,3,4]),
Promise.resolve([0,4,3]),
Promise.resolve(undefined)
]).then(function(results){
return Promise.all(_(results).flatten().map(result => {
if(result === 0) return Promise.reject()
}))
});
}
check().then(function(){
document.write('All Success');
//lert("all success");
}, function(){
document.write('Failed');
})
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.2/lodash.js"></script>
Also you could use some
function(results){
return Promise.all(results.map(result => {
if([].concat(result).some(value => value === 0)) {
return Promise.reject()
}
}

Chaining Angular promise rejections

I have a chained promise and in the case of a rejection for either of the promises, I need to perform an async operation (get the translated error message). As I've already got a chained promise on success, I assume it's not possible to also chain on rejection - I am attempting to simply nest the async calls, but I'm not getting the resolved promise back from deferred.reject(deferredRejection.promise); below. Pointers appreciated!
login: function(email, password) {
var deferred = $q.defer();
AuthService.login(email, password).then(function(response) {
var user = {
'accountToken': response.accountToken,
'email': response.username,
'onboarded': response.onboarded,
'verified': response.verified
};
return SyncStorageService.write(SyncStorageService.storageKeys.user,
user);
}, function(error) {
// login failed
var deferredRejection = $q.defer();
$translate('ALERTS.LOGIN_FAILED').then(function(translatedValue) {
deferredRejection.resolve(translatedValue);
});
deferred.reject(deferredRejection.promise);
}).then(function(data) {
deferred.resolve(data);
}, function(error) {
// saving data failed
var deferredRejection = $q.defer();
$translate('ALERTS.UNKNOWN').then(function(translatedValue) {
deferredRejection.resolve(translatedValue);
});
deferred.reject(deferredRejection.promise);
});
return deferred.promise;
}
Updated Solution:
Based on the answer below, I was able to re-write the code as follows:
login: function(email, password) {
return AuthService.login(email, password).then(function(response) {
return {
'accountToken': response.accountToken,
'email': response.username,
'onboarded': response.onboarded,
'verified': response.verified
};
}).then(function(data) {
return SyncStorageService.write(SyncStorageService.storageKeys.user,
data);
});
}
Notes:
Both AuthService.login and SyncStorageService.write now reject promises with an Error object (e.g. new Error('ALERT.ERROR_MESSAGE');), which bubbles up through login to the controller (previously was doing the translation at the service level);
The controller that calls the login method has .then() and .catch() blocks - on a .catch(), the passed Error.message is translated and displayed.
It looks like you're not really chaining promises, and using the forgotten promise/deferred anti pattern. Making a few assumptions about how you actually want it to behave, and factoring out the calls to $translate, then something like the following I suspect is what you're after:
login: function(email, password) {
return AuthService.login(email, password).then(function(response) {
return {
'accountToken': response.accountToken,
'email': response.username,
'onboarded': response.onboarded,
'verified': response.verified
};
}, function() {
return $q.reject('ALERTS.LOGIN_FAILED');
}).then(function(user) {
return SyncStorageService.write(SyncStorageService.storageKeys.user, user).catch(function() {
return $q.reject('ALERTS.UNKNOWN');
});
}).catch(function(message) {
return $translate(message).then(function(translatedValue) {
return $q.reject(translatedValue);
});
});
}
The main things to keep in mind are:
If you definitely want to reject the derived promise, return $q.reject(error) from the success or error callback.
All the error callbacks above do this. The ones after attempted login or saving use the translation key as the error that will be eventually passed to the final catch callback. The success callback from $translate also does this to transform its resolved promise to a rejected one, so the final catch callback returns a rejected promise, so the calling code gets a rejected promise, and (presumably) shows the translated error to the user.
If you definitely want to resolve the derived promise, return anything that isn't a promise from he success or error callbacks. The derived promise will be resolved with that value. (This includes undefined if you don't have an explicit return value).
This is what is done above when returning the user return {'accountToken'.... in the first callback.
If you want to defer the resolution/rejection of a promise, return another promise from the success or error callback. Then the derived promise will be eventually resolved or rejected in whatever manner this other promise is resolved/rejected.
This is what's done above when returning SyncStorageService.write..., and when returning $translate(....

Categories

Resources