Chaining two promises - javascript

I have two promises
const promise_1 = this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
.then(ting => {
console.log(ting);
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
})})
.catch(error => {console.log(error)});
const promise_2 = this.connection.getAllPatientData()
.then( function(response) {
console.log("Dispatrinc a new server call")
console.log(response.data)
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
})})
.catch(error => console.log(error))
console.log("Done");
}
the first one will post some data to the server, and the second one queries the data to redownload
the new list. The second one is dependent on the first one. Problem is that the first promise is fulfilled after. Second promise is fulfilled first.
How can I chain these two promises together
so promise 2 waits on promise 1?

If both functions are unrelated, but promise_1 has to resolve first so that the patient exists, you can just wrap the promise creation inside a function and only call the promise_2 creation when promise_1 resolves:
const promise_1 = () => this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
.then(ting => {
console.log(ting);
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
})})
.catch(error => {console.log(error)});
const promise_2 = () => this.connection.getAllPatientData()
.then( function(response) {
console.log("Dispatrinc a new server call")
console.log(response.data)
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
})})
.catch(error => console.log(error));
promise_1().then( response => promise_2());
If promise_2 relies on the results of promise_1 to run, for example if promise_1 will return the patient id and you need that id to run promise_2 and only the result of promise_2 has to be available after both resolve, then you can modify the above a tiny bit to pass the parameter:
const promise_1 = () => this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
.then(ting => {
console.log(ting);
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
})})
.catch(error => {console.log(error)});
const promise_2 = patient_id => this.connection.getAllPatientData( patient_id )
.then( function(response) {
console.log("Dispatrinc a new server call")
console.log(response.data)
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
})})
.catch(error => console.log(error));
promise_1()
.then( patient_id => promise_2( patient_id ))
.then( patient_data => {
// handle patient data.
});
You could also restructure everything into more atomic functions, so each promise has one specific goal, so you can chain them all together. If you nest the structure differently, you can even save all of the responses and return all fo then at the end.
const create_patient_id = () => this.connection.insertPatientToDataBase(Store.getPotentialPatientID());
const create_patient = patient_id => Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: patient_id.data.password
});
const get_patients = () => this.connection.getAllPatientData();
const update_patients = patients => Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: patients.data
})
const workflow = () => create_patient_id()
.then( create_patient );
.then( get_patients )
.then( update_patients );
workflow();

When using then, you chain promises by creating the next one inside the previous resolver:
const promise_1 = this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
.then(ting => {
console.log(ting);
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
});
return this.connection.getAllPatientData();
})
.then(response => {
console.log("Dispatrinc a new server call");
console.log(response.data);
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
});
})
.catch(error => {console.log(error)});
whith async/await this may be easier on the eyes:
async insertAndGet() {
try {
const ting = await this.connection.insertPatientToDataBase(Store.getPotentialPatientID());
console.log(ting);
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
};
const response = await this.connection.getAllPatientData();
console.log("Dispatrinc a new server call");
console.log(response.data);
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
})};
} catch (error) {
console.log(error);
}
}

You can simply move second Promise into then section of the first one.
If first promise fails, second one is not executed, if it resolves successfully - second one will commence.
Code will look something like this:
const promise_1 = this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
.then(ting => {
console.log(ting);
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
});
const promise_2 = this.connection.getAllPatientData()
.then(response => {
console.log("Dispatrinc a new server call");
console.log(response.data);
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
});
})
.catch(console.log);
})
.catch(console.log);
console.log("Done");
}
You can also chain Promises passing results from one then to another like this:
SomePromiseFunc().then(result1 => SomeOtherPromiseFunc(result1)).then(result2=> doSmth(result2)).catch();
This way could be easier if you want to use result of 1st Promise inside the second one or if catch logic is the same for both of them.

Promise1()
.then(response => Promise2(response))
.catch(err => {
// do something with error
});
This waits until the first promise is resolved, then calls the second promise with the result. You don't have to pass along the result, if you don't need it .then(() => Promise2()). If Promise1 fails then Promise2 is never called.
Note: Apparently I wasn't verbose enough in my initial response, so let's break it down a little better.
First, wrap your promise calls so you can provide the extra functionality to each:
class MyCustomClass {
createNewPatient() { // maybe you pass it in? maybe it's always there?
// Guessing Store is outside the class, but available
return this.connection.insertPatientToDataBase(Store.getPotentialPatientID())
.then(ting => {
console.log(ting);
// Guessing Dispatcher and Constants are outside the class, but available
Dispatcher.dispatch({
actionType: Constants.CHANGE_POTENTIAL_PATIENT_PASSWORD,
payload: ting.data.password
});
})
.catch(error => {console.log(error)});
}
reloadResults() {
return this.connection.getAllPatientData()
.then( function(response) {
console.log("Dispatrinc a new server call")
console.log(response.data)
// Guessing Dispatcher and Constants are outside the class, but available
Dispatcher.dispatch({
actionType: Constants.CHANGE_ALL_PATIENTS,
payload: response.data
});
})
.catch(error => {console.log(error)});
}
// What you seem to be looking for
createAndReload() {
return this.createNewPatient()
.then(() => this.reloadResults())
.then(() => {
console.log('done');
});
}
}

Related

Data not returning from service to context when using promises

I'm getting some data from server and have set-up this service on client to request them accordingly:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
const { data } = await axios.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
return data
}
service is called within context:
const syncFollowedArtists = async () => {
await spotifyService
.serviceSyncFollowedArtists(user.userId)
.then(res => {
if (res.length === 0) return
dispatch({
type: 'SYNC',
data: res,
})
})
.catch(err => {
console.log(err)
})
}
It works fine as I want it to, however, before, I have set up the service to request data using promises:
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}
Even though I manage to obtain the data from server inside the service, when it's returned to the function in context, it's empty, undefined. Is threre any reason for this?
You are getting undefined because you are not returning anything from the function in the case of promises, unlike you are doing it in the first case
So just add a return keyword
const serviceSyncFollowedArtists = async userId => {
if (!userId) return
return await axios
.get(`${httpLink}/sync`, {
params: {
accessToken,
userId,
},
})
.then(res => {
return res.data
})
.catch(err => {
console.log(err.message)
})
}

Vue store dispatch error response not being passed to UI

I'm trying to get the error response from my Vue store dispatch method, into my component, so I can tell the user if the save failed or not.
store/userDetails.js
const state = {
loading: {
user_details: false,
}
}
const getters = {
// Getters
}
const actions = {
save({commit, dispatch, rootState}, payload) {
commit('setLoading', {name: 'users', value: true});
axios(
_prepareRequest('post', api_endpoints.user.details, rootState.token, payload)
).then((response) => {
if (response.data) {
commit('setState', {name: 'user_details', value: response.data.units});
commit('setLoading', {name: 'user_details', value: false});
dispatch(
'CommonSettings/setSavingStatus',
{components: {userDetails: "done"}},
{root:true}
);
}
}).catch((error)=> {
console.log(error)
return error
}
)
}
My component method
views/Users.vue
send() {
this.$store.dispatch({
type: 'Users/save',
userDetails: this.current
}).then(response => {
console.log(response)
});
},
Above, I'm logging out the response in two places.
The response in my store/userDetails.js file is logged out fine, but it's not being passed to my send() function in my component - it comes up as undefined. Any reason why it wouldn't be passed through? Is this the correct way to do this?
This works for me. Try this solution.
store.js
actions: {
save(context, payload) {
console.log(payload);
return new Promise((resolve, reject) => {
axios(url)
.then((response) => {
resolve(response);
})
.catch((error) => {
reject(error);
});
});
},
},
My Component method
App.vue
save(){
this.$store.dispatch("save", dataSendToApi).then((response)=>{
console.log(response)
})
}
Try returning axios call in the Store Action:
// add return
return axios(
_prepareRequest('post', api_endpoints.user.details, rootState.token, payload)
)
.then() // your stuff here
.catch() // your stuff here
If that won't work, use Promise in the Store Action. Like this:
return new Promise((resolve, reject) => {
return axios() // simplify for readibility reason, do your stuff here
.then((response) => {
//... your stuff here
resolve(response) // add this line
})
.catch((error) => {
// ... your stuff here
reject(error) // add this line
})
})
you should return a promise, reference link:vue doc

its passing as combined values 4,5,6

I am new to promise.
I need to make two different api calls.
from the result of first api call I am getting id in the variable firstAPIid,
https://reqres.in/api/users?page=2
I need to pass this id firstAPIid to the second api call.
but the problem is its passing as combined values 4,5,6 https://jsonplaceholder.typicode.com/comments?postId=4,5,6
from the second api call I need to retrieve email and display it in the browser.
do I need to use promise or async or with redux itself can I achieve it.
I researched and referred the below links but still no luck
https://medium.com/#bluepnume/learn-about-promises-before-you-start-using-async-await-eb148164a9c8
can you tell me how to fix it.
providing my code snippet and sandbox below
https://codesandbox.io/s/redux-async-actions-xjdo7
<FetchButton
onFetchClick={() => {
store.dispatch(dispatchFunc => {
dispatchFunc({ type: "FETCH_DATA_START" });
axios
.get("https://reqres.in/api/users?page=2")
// axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log("response.data.data---->", response.data.data);
console.log(
"response.data.data[0].id---->",
response.data.data[0].id
);
dispatchFunc({
type: "RECEIVED_DATA",
payload: response.data.data
});
let firstAPIid = response.data.data.map(obj => {
return obj.id;
});
console.log("firstAPIid---->", firstAPIid);
return new Promise((resolve, reject) => {
//var url = `https://jsonplaceholder.typicode.com/comments?postId=3`;
var url =
`https://jsonplaceholder.typicode.com/comments?postId=` +
firstAPIid;
//response.data.data[0].id;
console.log("second url---->", url);
axios
.get(url)
.then(response => {
var lFilterData = "";
//memberGroupingHelper.filterData(response.data, additionalParams);
resolve(lFilterData);
})
.catch(error => {
if (error.response) {
console.log(
`############## service error from helpeeeeeer reject`
);
}
reject("");
});
});
})
.catch(err => {
dispatchFunc({ type: "FETCH_DATA_ERROR", payload: err });
});
});
}}
/>
I found your issue. It is happening because you are not processing the result of the promise. To do that just add the .then() and .catch() functions:
<FetchButton
onFetchClick={() => {
store.dispatch(dispatchFunc => {
dispatchFunc({ type: "FETCH_DATA_START" });
axios
.get("https://reqres.in/api/users?page=2")
// axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log("response.data.data---->", response.data.data);
console.log(
"response.data.data[0].id---->",
response.data.data[0].id
);
dispatchFunc({
type: "RECEIVED_DATA",
payload: response.data.data
});
let firstAPIid = response.data.data.map(obj => {
return obj.id;
});
console.log("firstAPIid---->", firstAPIid);
return new Promise((resolve, reject) => {
//var url = `https://jsonplaceholder.typicode.com/comments?postId=3`;
var url =
`https://jsonplaceholder.typicode.com/comments?postId=` +
firstAPIid;
//response.data.data[0].id;
console.log("second url---->", url);
axios
.get(url)
.then(response => {
var lFilterData = "";
//memberGroupingHelper.filterData(response.data, additionalParams);
resolve(lFilterData);
})
.catch(error => {
if (error.response) {
console.log(
`############## service error from helpeeeeeer reject`
);
}
reject("");
});
}).then((previousResponse) => {
//Here you resolved the promise with the resolve value above
console.log(previousResponse)
}).catch((error) => {
//Here you resolved the promise with the reject value above
console.log(error);
});
})
.catch(err => {
dispatchFunc({ type: "FETCH_DATA_ERROR", payload: err });
});
});
}}
/>
I am not seeing any use of the Promise because what you want to achieve can be done just with axios.
EDIT:
Just with axios you can get it. Modify as below:
<FetchButton
onFetchClick={() => {
store.dispatch(dispatchFunc => {
dispatchFunc({ type: "FETCH_DATA_START" });
axios
.get("https://reqres.in/api/users?page=2")
// axios.get('https://jsonplaceholder.typicode.com/posts')
.then(response => {
console.log("response.data.data---->", response.data.data);
console.log(
"response.data.data[0].id---->",
response.data.data[0].id
);
//First of all we'll create the number of requestes base on the previous Response
const promises = response.data.data.reduce((previousValue, { id }) => {
previousValue.push(axios.get(`https://jsonplaceholder.typicode.com/comments?postId=${id}`));
return previousValue;
},[]);
//We use the built in function to fetch the data
axios.all(promises)
.then((responses) => {
//Here you have all responses processed
const emailsMapped = responses.reduce((previousValue, { data }) => {
const emails = data.map(({ email }) => email)
previousValue.push(...emails);
return previousValue;
}, [])
//You send the emails you want
dispatchFunc({
type: "RECEIVED_DATA",
payload: emailsMapped
});
console.log(emailsMapped);
})
})
.catch(err => {
dispatchFunc({ type: "FETCH_DATA_ERROR", payload: err });
});
});
}}
/>
Also modifies this line in DataList without the first_name
listItems.push(<div key={fetchedDataId++}>{elem}</div>);

How to setState after a loop of async functions

The closest answer I could find was this, which didn't help since I need to setState: How do I run a function after using array.map?
I think the answer should be simple, but I'm pretty new to Javascript. I'm trying to move the setState for isLoading to AFTER I've pulled all of the profiles.
componentDidMount() {
console.log('MatchesScreen init props: ', Object.keys(this.props))
Object.keys(this.props.profile.profile.matches).map((username) => {
console.log('match', username)
url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username
fetch(url, {
method: 'GET',
})
.then((response) => response.json())
.then((responseJson) => {
this.setState({
isLoading: false,
})
this.props.addMatch(responseJson)
})
.catch((error) =>{
console.error(error);
})
})
}
I've tried various things like appending a .then() to the map function, but so far no luck.
You could return each promise inside the .map() function, which would leave you with an array of promises. Once you have that, you can use Promise.all() to wait for all the promises in the array to resolve.
componentDidMount() {
console.log('MatchesScreen init props: ', Object.keys(this.props))
// Put all promises into an array
const promisesArray = Object.keys(this.props.profile.profile.matches).map((username) => {
console.log('match', username)
url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username;
// Return each promise
return fetch(url, {
method: 'GET',
})
.then((response) => response.json())
.then((responseJson) => {
this.props.addMatch(responseJson)
})
.catch((error) =>{
console.error(error);
});
});
// Wait for all promises in array to resolve
Promise.all(promisesArray)
.then(() => {
// This will execute once all promises have resolved
this.setState({
isLoading: false,
});
})
.catch(e => console.error(e));
}
Try using the async/await pattern as follows:
async componentDidMount() {
...
Object.keys(this.props.profile.profile.matches).map((username) => {
...
await fetch(url, {
...
then move your setState method into its own callback, which you can call in your .then() statements following your fetch.
I like this reference: https://alligator.io/js/async-functions/
Try wrapping the Object.keys() in a while loop with an if statement at the end.
var profilesMatched = 0;
while(profilesMatched < Object.keys(this.props.profile.profile.matches).length){
Object.keys(this.props.profile.profile.matches).map((username) => {
console.log('match', username)
url = 'https://xxxxxxx.execute-api.us-west-2.amazonaws.com/prod/profile?username=' + username
fetch(url, { method: 'GET', })
.then((response) => {response.json()})
.then((responseJson) => {
this.props.addMatch(responseJson);
profilesMatched++;
})
.catch((error) => {
console.error(error);
});
});
if(profilesMatched == Object.keys(this.props.profile.profile.matches).length){
this.setState({
isLoading: false,
})
}
}

Axios prints value on console but returns undefined

I have quite an issue for some time and is getting on my nerves and it doesn't make sense. I have used axios on my react frontend and it works perfect when assigning the get value to the state. But when using it in a normal javascript code, I appear to have this following issue: i can print the object's value in the console but it will return only undefined.. Here is my code:
login = () => {
let data;
axios.get('https://myaddress/authenticate')
.then(response => {
data = response;
console.log('data here', data);
})
.catch(error => {
console.error('auth.error', error);
});
console.log('eee', data);
return data;
};
Here we are talking about axios strictly.
You can't return an ajax response because it's asynchronous. You should wrap your function into a promise or pass a callback to login
UPDATE: As #Thilo said in the comments, async/await would be another option, but it will let you set the response to data tho ...
1. Wrap into a promise
login = () => new Promise((resolve, reject)=>{
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
reject(error)
});
});
// Usage example
login()
.then(response =>{
console.log(response)
})
.catch(error => {
console.log(error)
})
2. Pass a callback
login = (callback) => {
axios.get('https://myaddress/authenticate')
.then(response => {
callback(null,response)
})
.catch(error => {
callback(error,null)
});
};
// Usage example
login((err, response)=>{
if( err ){
throw err;
}
console.log(response);
})
3. Async/Await
login = async () => {
// You can use 'await' only in a function marked with 'async'
// You can set the response as value to 'data' by waiting for the promise to get resolved
let data = await axios.get('https://myaddress/authenticate');
// now you can use a "synchronous" data, only in the 'login' function ...
console.log('eee', data);
return data; // don't let this trick you, it's not the data value, it's a promise
};
// Outside usage
console.log( login() ); // this is pending promise
In ES7/ES8 you can do async/await like a boss:
login = () => {
return new Promise((resolve, reject) => {
axios.get('https://myaddress/authenticate')
.then(response => {
resolve(response)
})
.catch(error => {
console.error('auth.error', error);
reject(error)
});
});
};
async function getData() {
try{
const data = await login()
} catch(error){
// handle error
}
return data;
}
getData()
.then((data) => console.log(data));

Categories