I have two api call.
I want to do some calculation based on the results of both api.
I am using Promise.all() for waiting for both promises to resolve.
const getHashTagList = async () => {
loader.start();
try {
await getAllHashTags().then((response: any) => {
setHashtagList([...response?.data]);
});
} catch (err) {
} finally {
loader.stop();
}
};
const getUserFollowingHT = async () => {
loader.start();
try {
await getUserDetails().then((response: any) => {
setUserFollowingHT([...response?.data?.followingHashtags]);
});
} catch (err) {
} finally {
loader.stop();
}
};
For calling these 2 promises I am using below syntax:
useEffect(() => {
//getHashTagList();
// getUserFollowingHT();
Promise.all([getHashTagList, getUserFollowingHT]).then(
(combineResp) => {
console.log(combineResp);
}
);
}, []);
But in the output I am getting function declaration syntax.
It is not able to get call those promises.
Try this
useEffect(() => {
(async () => {
const values = await Promise.all([getHashTagList, getUserFollowingHT]);
console.log(values);
})();
}, []);
Related
Inside of my useEffect hook I am trying to call an api request that is inside of .map but the rest of the function isn't waiting for the response. I've tried making the .map async but then the rest of the function returns Promises what is the correct way of doing this so that my api request can be called and then proceed with the rest of the code?
const getData = async (id) => {
const myData = await api.get(
'/api/request/id'
);
return myData;
};
useEffect(() => {
const myData = sampleData.map((item)
getData(item.id).then((response) => {
console.log(response.data.data);
return response.data.data
})
const myThings = myItem.things.map((thing) => {
if (thing.type === 'sampleType1') {
return [thing.name, thing.value];
} else (thing.type === 'sampleType2') {
return [
thing.name,
thing.content.name,
];
}
});
setData = {myThings, myData}
}, []);
You are going to want to wait for all those promises to resolve before mapping over them, so this is a great use case for Promise.all:
useEffect(() => {
async function fetchData() {
const myData = await Promise.all(sampleData.map((item) =>
getData(item.id).then((response) => {
console.log(response.data.data);
return response.data.data
}));
const myThings = myItem.things.map((thing) => {
if (thing.type === 'sampleType1') {
return [thing.name, thing.value];
} else (thing.type === 'sampleType2') {
return [
thing.name,
thing.content.name,
];
}
});
setData = {myThings, myData}
}
fetchData();
}, []);
I would like to return an object from the the async / await function A to pass it to another function.
Currently what I get as a result is Promise{ <pending> }' or undefined.
function A:
const parseRss = data => data.forEach(rssLink => {
const getFeed = async () => {
try {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: []
}
}
feed.items.forEach(item => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`)
});
return emailContent;
} catch (e) {
console.error(e);
}
};
return (async () => {
return await getFeed();
})();
});
Function B:
try {
const data = await getDataWithRss();
const emailData = await parseRss([{rss:'http://reddit.com/.rss'}]); // emailData is undefined
return formatEmail(emailData);
} catch (error) {
console.log(error);
}
How do I return emailContent from function A to use it in function B?
Thanks!
Since you made getFeed as async, no need another async. You are looping through, so return an array of promises. Once the you call use Promise.all to resolve. Since there could be multiple urls to fetch.
const parseRss = (data) =>
data.map((rssLink) => {
const getFeed = async () => {
try {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: [],
},
};
feed.items.forEach((item) => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`);
});
return emailContent;
} catch (e) {
console.error(e);
}
};
return getFeed();
});
try {
const data = await getDataWithRss();
const emailData = await Promise.all(parseRss([{rss:'http://reddit.com/.rss'}])); // emailData is undefined
return formatEmail(emailData);
} catch (error) {
console.log(error);
}
await will not work inside a forEach loop. Use a for...in loop instead.
actually, getFeed() is not necessary inside inner scope, you can use async in map callback:
const parseRss = data => data.map(async rssLink => {
const feed = await rssParser.parseURL(rssLink.rss);
const emailContent = {
emailBody: {
title: feed.title,
content: []
}
};
feed.items.forEach(item => {
feedObj.emailBody.content.push(`${item.title} : ${item.link}`)
});
return emailContent;
});
Supposedly, the component needs to wait for notificationsMixin to finish before it changes the route, but it doesn't:
Mixin:
export const notificationsMixin = {
methods: {
async notificationsMixin () {
this.$Plugins.PushNotifications.register()
this.$Plugins.PushNotifications.addListener('registration', async (token) => {
await this.API(token.value)
})
this.$Plugins.PushNotifications.addListener('registrationError', () => {
//
})
},
async API (token) {
await this.$axios.post('https://api.fexler.com/?action=notifications', token).then(async (response) => {
if (response.data) {
await this.$Plugins.Storage.set({
key: 'token',
value: JSON.stringify(token)
})
}
})
}
}
}
Component:
this.notificationsMixin().then(async () => {
this.$router.push('/profile')
})
This function resolves immediately.
async notificationsMixin () {
this.$Plugins.PushNotifications.register()
this.$Plugins.PushNotifications.addListener('registration', async (token) => {
await this.API(token.value)
})
this.$Plugins.PushNotifications.addListener('registrationError', () => {
//
})
},
Try adding await
async notificationsMixin () {
try {
await this.$Plugins.PushNotifications.register()
const token = await this.$Plugins.PushNotifications.addListener('registration')
await this.API(token.value)
this.$Plugins.PushNotifications.addListener('registrationError', () => {
//
})
}
catch (e) {
// handle error
}
}
I'm not 100% familiar with this plugin you are using, so you may have
to tweak the code a bit. But this should give you an idea of what to
do.
As an extra tip, it's not great practice (IMO) to mix then with await. Pick one and stick with it.
And you don't need async here:
this.notificationsMixin().then(async () => {
this.$router.push('/profile')
})
change to:
this.notificationsMixin().then(() => {
this.$router.push('/profile')
})
I have a function which checks whether a device is online or not. Below is the code.
const ping = require('ping');
export function findDevices(device) {
try {
const hosts = [device];
let result = null;
hosts.forEach((host) => {
ping.promise.probe(host)
.then((res) => {
console.log(res.alive)
result = res.alive;
return {
Status: result
}
});
});
} catch (err) {
logger.error(err, '[ config - findDevices() ]');
console.error(err);
return {
Status: "Failed"
}
}
}
I am calling this function in a redux action like this:
export function start(device) {
return dispatch => {
const status = Connectionstatus.findDevices(device);
return dispatch({
type: actionTypes.CONNECTIONSTATUS,
payload: {
ConnectionStatus: status
}
})
};
}
I am expective the status variable to be either true or false. But i am getting as undefined even though i am returning the value inside then of the promise function. i have tried awaiting this call and still its not working. Any help would be much appreciated. Thanks.
If that's the case you can do like this
const getStatus = async () => {
try {
const hosts = [device];
const promises = [];
hosts.forEach((host) => {
promises.push(ping.promise.probe(host));
});
const result = await Promise.all(promises);
const status = result.map((r) => { return r.alive; });
return status;
} catch (err) {
logger.error(err, '[ config - findDevices() ]');
return { status: 'Failed' };
}
};
Not 100% sure what all the vars are, but have you considered using async/await to simplify things a bit like this?
const getStatus122 = async device => {
return await Promise.all([device].map(ping.promise.probe))
.then(({ alive }) => alive)
.then(Status => ({ Status }))
.catch(error => {
logger.error(error, '[ config - findDevices() ]');
return { Status: 'Failed' };
})
}
More on that here: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/async_function
With Promises you should inspect the promised result either in when or catch callback functions. With async/await the code may look a bit simpler. Here is the version with explicit promises.
const ping = require('ping');
const Connectionstatus = {
findDevices: (device) => {
return ping.promise.probe(device).then((res) => {
const result = res.alive;
console.log(result);
return {
Status: result,
};
}).catch((err) => {
logger.error(err, '[ config - findDevices() ]');
console.error(err);
return {
Status: "failed"
}
});
}
}
export function start(device) {
return dispatch => {
Connectionstatus.
findDevices(device).
then((status) => {
dispatch({
type: actionTypes.CONNECTIONSTATUS,
payload: {
ConnectionStatus: status
}
})
});
};
}
You may see that error handling moved to the catch callback function while the dispatch is done in the then callback function. And this is the answer to your question.
I am promisifying the React Native AsyncStorage getItem method but I am being warned that it is returning a possible unhandled promise rejection. Here's what I'm doing, what's wrong with my code?
In App.js ComponentDidMount()
componentDidMount() {
ConnectyCube.init(...config);
authInitialization = async () => {
const locallyStoredPhoneNumber = await getStoredPhoneNumber();
console.log(locallyStoredPhoneNumber);
authorizeFirebase(this.getFirebaseAccessToken);
this.props.authorizing(true);
}
authInitialization();
}
Then in localStorage.js
export const getStoredPhoneNumber = () => {
return new Promise((resolve, reject) => {
AsyncStorage.getItem('#phone_number', (error, result) => {
result ? resolve(result) : reject(error);
})
})
}
Thanks in advance.
UPDATE
I have now added error handling:
export const getStoredPhoneNumber = () => {
return new Promise((resolve, reject) => {
AsyncStorage.getItem('#phone_number', (error, result) => {
result ? resolve(result) : reject(error);
})
}).catch(error => console.error(error))
}
Seems to work - here's my extra logic that depends on the result of the AsyncStorage call:
componentDidMount() {
ConnectyCube.init(...config);
authInitialization = async () => {
const locallyStoredPhoneNumber = await getStoredPhoneNumber();
locallyStoredPhoneNumber !== undefined
? authorizeFirebase(this.getFirebaseAccessToken) && this.props.authorizing(true)
: this.setState({ newUser: true })
}
authInitialization();
}
Seems like this should work:
async componentDidMount() {
ConnectyCube.init(...config);
try {
const locallyStoredPhoneNumber = await AsyncStorage.getItem('#phone_number');
locallyStoredPhoneNumber !== undefined
? authorizeFirebase(this.getFirebaseAccessToken) && this.props.authorizing(true)
: this.setState({ newUser: true })
} catch (e){
// handle error
}
}
One way to handle promise rejection would be to use try...catch block where your promise is being returned.
try{
const locallyStoredPhoneNumber = await getStoredPhoneNumber();
} catch(error){
//Error handling code here
}
You need to 'catch' any errors which might be thrown and handle them (otherwise React will complain):
componentDidMount() {
authInitialization = async () => {
try {
const locallyStoredPhoneNumber = await getStoredPhoneNumber();
...
} catch (e) {
console.log(e) //handle error }
}
authInitialization();
}
}