For this project I am using wretch, which is a wrapper around fetch
This is a breakout of my code:
I have the wretch calls on a seperate service file to separate the render functionality from the wretch functionality.
I am exporting
export const wretchFunc = var => {
return wretch(url)
.json({
var,
})
.get()
.json()
};
The problem is with the second file: The function2 renders the result of the wretch function, I do resolve the promise and I get the result that I want but when I call it from function1 the return value is undefined even-though placing a console.log inside function2 gives me the boolean that I am looking for.
I have a function1 that returns:
return (function2 || function3)
and the function2 renders the result of wretchFunc and something like this:
function function2(state) {
const var = fun(state);
if (!var) {
return false;
}
wretchFunc(var).then(json => {
return JSON.parse(json).isTrue;
});
}
My assumption is that function one gets executed before receiving the result of the function2 but I am not sure what to do.
Edit:
I tried doing:
return wretchFunc(var).then(json => {
return JSON.parse(json).isTrue;
});
}
Which gives me another promise that I can resolve on the upper function, but since I have a previous condition if(!var) that returns false that would make the function return 2 different things. is there a way that I can cast the value of the promise in function2 and force function1 to wait for its result.
Thanks
Try wrapping into new Promise and returning it
function function2(state) {
return new Promise((res, rej) => {
const var = fun(state);
if (!var)
res(false);
wretchFunc(var)
.then(json => resolve(JSON.parse(json).isTrue)
.catch(err) => rej(err));
})
}
Related
In JS, let's say I call a promise in a 'fire and forget' way. I don't care if it was successful or not, and I don't care what it returns as I want to return the same value anyways.
I can call
return myPromise().then(() => foo).catch(() => foo);
Is there a way to not repeat then then and catch parts?
What I've tried
I thought about using finally, thinking that it will take what finally returns (similar to what Java does by taking the return value of the finally block) :
return myPromise().finally(() => foo);
But it turns out it didn't do what I expected. According to mdn, this return value will be used to reject in case the original promise rejected.
You can declare your result returning function once and then re-use it twice for the .then() and .catch() handlers
const myReturn = () => foo;
return myPromise()
.then(myReturn)
.catch(myReturn);
You can further shorten this by using both parameters of .then() which handle both the success and failure path:
const myReturn = () => foo;
return myPromise()
.then(myReturn, myReturn);
If you find needing this a lot, you might make a small library function that takes a value and returns two functions that both just evaluate to it:
const doubleThunk = val =>
[() => val, () => val];
Which would be used like this:
return myPromise()
.then(...doubleThunk(foo));
From #deceze's comment and #Bergi clarification:
myPromise()
.catch(() => {}) // ignore any error
.then(() => foo) // always return foo
You could have a look at Promise.allSettled if you're targeting newer browsers or Node.js versions.
This function will return a Promise that resolves whether or not the passed Promise resolves or rejects.
function foo(results) {
console.log('foo():', ...results)
}
// Success path
Promise.allSettled([Promise.resolve('Yay')]).then(foo)
// Failure path
Promise.allSettled([Promise.reject('Doh')]).then(foo)
.as-console-wrapper { max-height: 100% !important; }
I have the following JScode
function DetermineLoggedUser(){
return $.post('determineLoggedUser.php',{
}).then((result) => {
loggedUser = result;
})
The php looks like this:
<?php
session_start()
if(ISSET($_SESSION["loggedUser"])) {
echo $_SESSION["loggedUser"];
}else{
echo "'userNotLogged'";
}
?>
Now, I want DetermineLoggedUser() to return the value of loggedUser after it has been set by $.post AJAX call.
At the same time, I want the function calling DetermineLoggedUser() to wait, using async/await.
So it would look kinda like this:
async function callingSeveralFunctions(){
//some functions
var result = await determineLoggedUser();
//some other functions which need to wait for determineLoggedUser()
}
function DetermineLoggedUser(){
return $.post('determineLoggedUser.php',{
}).then((result) => {
loggedUser = result;
})
callingSeveralFunctions();
So, since I need to return the promise created by the AJAX call in order to make "await" work, I wonder how I can at the same time return the value set to loggedUser inside determineLoggedUser()?
You've got the first bit right - you're correct in returning the Promise from your DetermineLoggedUser() function. The calling code can then attach a .then() to that Promise object (as opposed to attaching it within the DetermineLoggedUser function, which isn't so useful) in which you can retrieve the value, and then execute whatever other functions you need which depend on it.
function callingSeveralFunctions(){
//some functions
var promise = determineLoggedUser();
promise.then((response) => {
loggedUser = response;
//some other functions which need to wait for determineLoggedUser() - calls to these need to go inside the callback, here
});
}
function DetermineLoggedUser(){
return $.post('determineLoggedUser.php',{});
}
callingSeveralFunctions();
You can't escape the fact that it's asynchronous, but you can work with it better.
Each promise, need to return something, in your case, then you call you file determineLoggedUser.php he go directly into your then function, expected that you return nothing.
Try something like that :
const ajax = $.post('determineLoggedUser.php',{
}).then(result => {
return res.json(); // In case of backend return json...
}).then(data => {
return console.log(data);
});
console.log(ajax)
I have some data in a array.
let data = ['firstData', 'secondData'];
The first object (firstData) always exists, secondData could be null. So I always use that to call my async function like:
myAsyncFunction(data[0]).then(result => {
//do something here
});
If data[1] exists, I wanna call myAsyncFunction with data[1].
My current solution is with nested promises. Like this:
myAsyncFunction(data[0]).then(result => {
return result;
}).then(result => {
if(data[1] !== null){
myAsyncFunction(data[1].then(resultTwo => {
//dostuff with data
});
}
});
I don't really like this solution, but it does work. It must be a better way tho. result is always a object. I tried Promise.all but it does not work. I think it's a problem with "race condition" of some sort (I am on thin ice here).
Is my current solution the only one?
Here is what myAsuncFunction looks like:
myAsyncFunction(personData){
return new Promise<any> ((resolve, reject) => {
//Assingen private variables
secondAsyncFunction(somePersonData).then(result =>
{
//Do some sync stuff
return someNewData; //not a promise
})
.then(thirdAsyncFunction)
.then(data => {
resolve(data);
})
.catch(error => {
reject(error);
});
});
Promise.all is designed to be used when you have a dynamic number of promises in an array, and you want to combine them into a promise which resolves when all of the promises in the array have resolved.
According to your use case, you should be able to use it like this:
data = data.filter(x => x !== null);
Promise.all(data.map(myAsyncFunction)).then((results) => {
const [resultOne, resultTwo] = results;
if (resultTwo) {
// handle resultTwo
}
// handle resultOne
});
Given that data is known statically before the promise result, you don't need to put the condition inside the then callback - you can make the whole chaining conditional:
var promise = myAsyncFunction(data[0]);
if(data[1] !== null){
promise.then(result =>
myAsyncFunction(data[1])
).then(resultTwo => {
//dostuff with data
});
}
In general, notice that nesting is not a bad thing, it is required when you want to branch control flow. Just don't forget to always return your promises from all (callback) functions.
You could just simply do:
const stuffOnlyRelatedToSecondData = result2 => /*do something*/
myAsyncFunction(data[0]).then(result => {
if (data[1] === null) {return null}
return myAsyncFunction(data[1]).then(stuffOnlyRelatedToSecondData)
}).then(/*Anything to do after [1] or [1,2]*/)
This way you can use the same chain and the two possible cases will look like:
myAsyncFunction(data[0]) --> END
myAsyncFunction(data[0]) --> myAsyncFunction(data[1]) --> END
Edit:
It seems that myAsyncFunction may have a promise leak, try using something like this instead:
const myAsyncFunction = personData => {
//Assigning private variables
return secondAsyncFunction(somePersonData).then(result => {
//Do some sync stuff
return someNewData; //not a promise
})
.then(thirdAsyncFunction)
}
We can write it this way because secondAsyncFunction kicks off a new Promise, hence we don't need another Promise wrapper around it. And the catch can be put in the parent Promise chain itself which executes myAsyncFunction
function f () {
return new Promise(function (resolve, reject) {
resolve(4);
})
}
function g () {
return f().then((res) => {return res;})
}
console.log(g());
This returns Promise { <pending> }
If I returned res(in the then) and then returned f(), why isn't the output 4?
a valid answer would be:
function f() {
return new Promise(function(resolve, reject) {
resolve(4);
})
}
function g() {
return f().then((res) => {
return res;
})
.then((res) =>{
console.log(res);
})
}
g()
Why? Any time you return from inside a then statement in a promise, it passes it to the next statement (then or catch). Try commenting out return res and you'll see that it prints undefined.
==============
However, with ES7 we can use async/await. We can replicate the above using the following code:
function f() {
return new Promise(function(resolve, reject) {
resolve(4);
});
}
async function g() {
var a = await f();
// do something with a ...
console.log(a);
}
g();
It's important to note that console.log(g()) still returns a promise. This is because in the actual function g, resolving the promise gets delayed and therefore doesn't block the rest of our code from executing but the function body can utilize the returned value from f.
NOTE: to run this you need node 7 and it should be executed with the --harmony-async-await option.
===========
EDIT to include new code snippet
Look at the following code. You must use then to access the previous objects - however, where you access it in this case is up to you. You can call then on each promise inside of Promise.all, in this case .then((userVictories) => ...).then(...) or once Promise.all returns. It's important to note that Promise.all returns once all promises it contains resolve.
var membersArray = groupFound.members;
Promise.all(membersArray.map((member) => {
return db.doneTodo.find({ 'victor._id': member._id }).then((userVictories) => {
return {
email: member.email,
victories: userVictories.length,
}
}).then(obj => {
/*
obj is each object with the signature:
{email: '', victories: ''}
calling this then is optional if you want to process each object
returned from '.then((userVictories) =>)'
NOTE: this statement is processed then *this* promise resolves
We can send an email to each user with an update
*/
});
}))
.then((arr) => {
/*
arr is an array of all previous promises in this case:
[{email: '', victories: ''}, {email: '', victories: ''}, ...]
NOTE: this statement is processed when all of the promises above resolve.
We can use the array to get the sum of all victories or the
user with the most victories
*/
})
Let's look at jQuery first as an introduction to learning promises.
What does this code return? What is the value of result?
var result = $('body');
Hint: It won't be the <body/> body HTML element.
result is a jQuery collection object. Internally it holds a reference to the body tag. But the actual result object is a collection.
What does this return?
var result = $('body').css('background', 'red');
Again, it returns a jQuery collection.
And this?
var result = $('body').css('background', 'red').animate({height: "20px"});
Same thing. A jQuery collection.
Now, what does this promise based code return?
var result = new Promise();
It's probably clear this returns a promise. But what about this code?
var result = new Promise().resolve().then(() => {
return 'Hello';
});
What is the value of result now? Hint: It's not the string 'Hello'.
It's a promise!
What does this return?
var result = new Promise().resolve().then(() => {
return new Promise().resolve();
}).then(() => {
return 'Hello';
}).catch(() => {
console.log('Something went wrong');
});
It returns a promise! Promises let us access values in functions that are called at later times. Until the function is executed, you won't have access to whatever the promise "returns," or "resolves" with. Once you enter a promise chain, you always have to use .then(fn) to handle the next step in the program flow.
Javascript is asynchronous. All top level code is executed in order without pausing. The promise resolves at a later time, long after your console.log has finished executing. To get values back, you need to stay in promise chain land:
g().then( result => console.log(result) );
I'm trying to write a function that doesn't return it's value until a Promise inside the function has resolved. Here's a simplified example of what I'm trying to do.
'use strict';
function get(db, id) {
let p = db.command('GET', 'group:${id}');
p.then(g => {
g.memberNames = [];
g.members.forEach(id => {
User.get(db, id)
.then(profile => g.memberNames.push(profile.name))
.catch(err => reject(err));
});
return g;
});
}
It's a function that requests a group id and returns the data for that group. Along the way it's also throwing in the user's names into the data structure to display their names instead of their user id. My issue is that this is running asynchronously and will skip over the .then callbacks. By the time it gets to return g none of the callbacks have been called and g.memberNames is still empty. Is there a way to make the function wait to return g until all callbacks have been called?
I've seen a lot of stuff about await. Is this necessary here? It's highly undesired to add other libraries to my project.
Since your operation to return all the profile names is also async you should return a Promise fulfilled when all the other async operations complete (or reject when one of them is rejected) done with Promise.all
function get(db, id) {
let p = db.command('GET', 'group:${id}');
return p.then(g => {
return Promise.all(g.members.map(id => {
// NOTE: id is shadowing the outer function id parameter
return User.get(db, id).then(profile => profile.name)
})
})
}
Is there a way to make the function wait to return g until all callbacks have been called?
Yes, there is. But you should change your way of thinking from "wait until all the callbacks have been called" to "wait until all the promises are fulfilled". And indeed, the Promise.all function trivially does that - it takes an array of promises and returns a new promise that resolves with an array of the results.
In your case, it would be
function get(db, id) {
return db.command('GET', 'group:${id}').then(g => {
var promises = g.members.map(id => {
// ^^^ never use `forEach`
return User.get(db, id).then(profile => profile.name);
// ^^^^^^ a promise for the name of that profile
});
//
return Promise.all(promises).then(names => {
// ^^^^^^^^^^ fulfills with an array of the names
g.memberNames = names;
return g;
});
});
}