How to get the result of async / await function? - javascript

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;
});

Related

How to wait for all promises to resolve

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);
})();
}, []);

Async function, do something after the map function is finished

async function testing(summoner_name) {
try {
var match;
let summoner = {
name: [summoner_name],
};
const id = await fetchAccountID(summoner_name);
const matchList = await fetchMatches(id);
Object.keys(matchList.matches).map((key, i) => {
setTimeout(async function () {
match = await fetchMatch(matchList.matches[key].gameId);
summoner = await getMatchStats(
match,
matchList.matches[key].champion,
summoner
);
}, i * 100);
});
} catch (error) {
console.log(error);
}
}
I would like to do something after the map function is done iterating over all the keys, how can I achieve that?
Do you mean this?
async function testing(summoner_name) {
try {
let summoner = {
name: [summoner_name],
};
const id = await fetchAccountID(summoner_name);
const matchList = await fetchMatches(id);
//Promise in Serial
for (const key of Object.keys(matchList.matches)) {
const match = await fetchMatch(matchList.matches[key].gameId);
summoner = await getMatchStats(
match,
matchList.matches[key].champion,
summoner
);
}
} catch (error) {
console.log(error);
}
}

Problem with .push with Asynchronous function

The Problem is with the uplines.push.
I always get an empty uplines array so the last part of the code doesn't run. The promises resolve later and I get the correct data. May I know how to go about doing it the correct way?
const getAllUplines = async () => {
uplines = [];
const findUser = async (userFid) => {
const userDoc = await firestore.collection("users").doc(userFid).get();
if (userDoc.exists) {
const user = { ...userDoc.data(), id: userDoc.id };
console.log(user);
uplines.push(user);
if (user.immediateUplineFid) {
findUser(user.immediateUplineFid); //self looping
}
} else {
console.log("No User Found");
return null;
}
};
sale.rens.forEach(async (ren) => {
findUser(ren.userFid);
});
console.log(uplines);
return uplines;
};
let uplines = await getAllUplines();
console.log(uplines);
uplines = uplines.filter(
(v, i) => uplines.findIndex((index) => index === v) === i
); //remove duplicates
uplines.forEach((user) => {
if (user.chatId) {
sendTelegramMessage(user.chatId, saleToDisplay, currentUser.displayName);
console.log("Telegram Message Sent to " + user.displayName);
} else {
console.log(user.displayName + " has no chatId");
}
});
There are a few things that you have missed out while implementing the async call, which are explained in the inline comments in the code snippet.
A short explanation for what happened in your code is that in the line sale.rens.forEach you are passing an async function in the argument, which does not make any difference to the function forEach, it will execute it without waiting for it to complete.
Therefore in my answer I am using Promise.all to wait for all the async function calls to complete before returning the result.
// This is wrapped in an immediately executed async function because await in root is not supported here
(async () => {
const mockGetData = () => new Promise(resolve => setTimeout(resolve, 1000));
const sale = {
rens: [
{ userFid: 1 },
{ userFid: 2 },
{ userFid: 3 }
]
};
const getAllUplines = async () => {
const uplines = [];
const findUser = async (userFid) => {
// Simulating an async function call
const userDoc = await mockGetData();
console.log("User data received");
uplines.push(`User ${userFid}`);
};
const promises = [];
sale.rens.forEach(ren => { // This function in foreach does not have to be declared as async
// The function findUser is an async function, which returns a promise, so we have to keep track of all the promises returned to be used later
promises.push(findUser(ren.userFid));
});
await Promise.all(promises);
return uplines;
};
let uplines = await getAllUplines();
console.log(uplines);
})();
In order to get the results of getAllUplines() properly, you need to add await to all async functions called in getAllUplines().
const getAllUplines = async () => {
uplines = [];
const findUser = async (userFid) => {
const userDoc = await firestore.collection("users").doc(userFid).get();
if (userDoc.exists) {
const user = { ...userDoc.data(), id: userDoc.id };
console.log(user);
uplines.push(user);
if (user.immediateUplineFid) {
await findUser(user.immediateUplineFid); //self looping
}
} else {
console.log("No User Found");
return null;
}
};
sale.rens.forEach(async (ren) => {
await findUser(ren.userFid);
});
console.log(uplines);
return uplines;
};

get the return value from async function without calling it again

Here is the code:
const onStartRecord = async() => {
try {
const path = Platform.select({
ios: `file:///audio/${filenameGenerator}.m4a`,
android: `file:///audio/${filenameGenerator}.mp4`,
});
const audioSet: AudioSet = {
AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
AudioSourceAndroid: AudioSourceAndroidType.MIC,
AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
AVNumberOfChannelsKeyIOS: 2,
AVFormatIDKeyIOS: AVEncodingOption.aac,
};
console.log('audioSet', audioSet);
const uri = await audioRecorderPlayer.startRecorder(path, audioSet);
audioRecorderPlayer.addRecordBackListener((e: any) => {
setAudioProp(audioProp => {
return { ...audioProp,
recordSecs: e.current_position,
recordTime: audioRecorderPlayer.mmssss(Math.floor(e.current_position)),
}
});
});
console.log(`uri: ${uri}`);
return uri
} catch (err) {
console.log(err);
return;
}
};
const audioPath = async() => {
const result = await onStartRecord();
return result;
}
const onSubmit = async() => {
const audiopath = await audioPath();
console.log("this is the audiopath", audiopath)
}
};
I can get what I want when I trigger the onSubmit function, but the problem is, it also trigger the onStartRecord function again which will cause error in my case, I just want to get the uri generated when the onStartRecord resolved, but I don't want to trigger it again, so what can I do if I need to use the onSubmit function and get the value from onStartRecord? thx !
Instead of returning uri, onStartRecord should assign it to a global variable.
Then audioPath() can return that variable.
let savedAudioPath;
const onStartRecord = async() => {
try {
const path = Platform.select({
ios: `file:///audio/${filenameGenerator}.m4a`,
android: `file:///audio/${filenameGenerator}.mp4`,
});
const audioSet: AudioSet = {
AudioEncoderAndroid: AudioEncoderAndroidType.AAC,
AudioSourceAndroid: AudioSourceAndroidType.MIC,
AVEncoderAudioQualityKeyIOS: AVEncoderAudioQualityIOSType.high,
AVNumberOfChannelsKeyIOS: 2,
AVFormatIDKeyIOS: AVEncodingOption.aac,
};
console.log('audioSet', audioSet);
const uri = await audioRecorderPlayer.startRecorder(path, audioSet);
audioRecorderPlayer.addRecordBackListener((e: any) => {
setAudioProp(audioProp => {
return { ...audioProp,
recordSecs: e.current_position,
recordTime: audioRecorderPlayer.mmssss(Math.floor(e.current_position)),
}
});
});
console.log(`uri: ${uri}`);
savedAudioPath = uri;
} catch (err) {
console.log(err);
return;
}
};
const audioPath = async () => savedAudioPath;

Node-Fetch Mapping Error - Cannot read property 'map' of undefined"

Getting an error with the "map" part when I try and run it Cannot read property 'map' of undefined"
The customers const is declared above so not sure. Where is the undefined is coming from? Does the map need declaring?
const AWS = require('aws-sdk'),
ses = new AWS.SES(),
fetch = require('node-fetch');
exports.handler = async (event) => {
console.log(event.customer_id);
const customers = await getCustomers();
customers.map(async customer => await sendEmailToCustomer(customer));
const customersEmailsPromises = customers.map(async customer => await sendEmailToCustomer(customer));
}
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
return json;
}
catch(e) {
throw e;
}
}
const sendEmailToCustomer = (customer) => new Promise((resolve, reject) => {
ses.sendEmail({
Destination:
{ ToAddresses: [customer.email] },
Message:
{
Body: { Text: { Data: `Your contact option is ${customer.customer_id}` } },
Subject: { Data: "Your Contact Preference" }
},
Source: "sales#example.com"
}, (error, result => {
if (error) return reject(error);
resolve(result);
console.log(result);
})
);
})
getCustomers doesn't return anything which means that customers is set to undefined.
Try this:
async function getCustomers() {
try {
const resp = await fetch('https://3objects.netlify.com/3objects.json');
const json = await resp.json();
return json;
}
catch(e) {
throw e;
}
}
You also have to return something from the function that you pass as a parameter to .map
customers.map(async customer => {
return await sendEmailToCustomer(customer);
});
or just:
customers.map(async customer => await sendEmailToCustomer(customer));
And since .map returns a new array (does not mutate the original array), you'll have to store the return value:
const customersEmailsPromises = customers.map(async customer => await sendEmailToCustomer(customer));

Categories

Resources