Async function, do something after the map function is finished - javascript

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

Related

Getting 400 error code when I run axios get request?

I write some code to getting info
const stock = await Stock.find({
exchange: exchange
});
// Here stock array length is 5300
stock.forEach(async (stockEl) => {
const EOD_API = process.env.EOD_HISTORICAL_API
const {data} = await axios.get(`https://eodhistoricaldata.com/api/fundamentals/${stockEl.code}?api_token=${EOD_API}&filter=General::Industry`);
console.log(data);
});
Here I place get request for every stock array element by forEach function. Then it give me error like image-
Click to see images
But When I place it outside of forEach function like this-
const EOD_API = process.env.EOD_HISTORICAL_API
const {data} = await axios.get(`https://eodhistoricaldata.com/api/fundamentals/${stockEl.code}?api_token=${EOD_API}&filter=General::Industry`);
console.log(data);
Then it gives no error. For Remembering Stock has 5300 element, that means axios run 5300 times.
Any solution or idea?
You need to make a few changes:
Replace forEach with for because forEach is not promise aware
Use try, catch => catch any errors
Use Promise.allSettled => it allows you to run all promisses together without waiting each other which in return will enhance your app performance. It returns an array with status ("fulfilled", "rejected")
const fetchSingleStockElement = async (stockEl) => {
try {
const EOD_API = process.env.EOD_HISTORICAL_API,
{ data } = await axios(
`https://eodhistoricaldata.com/api/fundamentals/${stockEl.code}?api_token=${EOD_API}&filter=General::Industry`
);
return data;
} catch (err) {
throw new Error(err);
}
};
const fetchAllStockData = async () => {
let promisesArray = [];
try {
//fetch stock array
const { data } = await Stock.find({
exchange: exchange
});
//fetch single stock
for (let i = 0; i < data.length; i++) {
promisesArray.push(fetchSingleStockElement(data[i].id));
}
const results = await Promise.allSettled(promisesArray);
console.log('results', results);
} catch (err) {
console.log('results error', err);
}
};
Here is a working example with fake API of 4466 entries:
const fetchSingleAirline = async (airlineId) => {
try {
const { data } = await axios(`https://api.instantwebtools.net/v1/airlines/${airlineId}`);
return data;
} catch (err) {
throw new Error(err);
}
};
const fetchAllAirlineData = async () => {
let promisesArray = [];
try {
const { data } = await axios('https://api.instantwebtools.net/v1/airlines');
for (let i = 0; i < data.length; i++) {
promisesArray.push(fetchSingleAirline(data[i].id));
}
const results = await Promise.allSettled(promisesArray);
console.log('results', results);
} catch (err) {
console.log('results error', err);
}
};
Doing await in forEach doesn't hold the process since forEach is not promise-aware. Try this instead:
(async () => {
for (let index = 0; index < stock.length; index++) {
const EOD_API = process.env.EOD_HISTORICAL_API
const {data} = await axios.get(`https://eodhistoricaldata.com/api/fundamentals/${stock[i].code}?api_token=${EOD_API}&filter=General::Industry`);
console.log(data);
}
})();
More information.

nodejs javascript promise resolve

I can't seem to figure out how to save the results of SomeQuery promise. Essentially I would like to take the value in res and pipe it into parseQuery function and return the final results. How do I make the parsed result accessible to an APIs response.
const neo4j = require('neo4j-driver')
var parser = require('parse-neo4j')
const astria_queries = require('./astriaQueries')
const uri = 'bolt://astria_graph:7687'
const user = 'xxx'
const password = 'xxx'
const someQuery = (query) => {
// run statement in a transaction
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password))
const session = driver.session({ defaultAccessMode: neo4j.session.READ })
const tx = session.beginTransaction()
tx.run(query)
.then((res) => {
// Everything is OK, the transaction will be committed
parseQuery(res)
})
.then(() => {
// Everything is OK, the transaction will be committed
})
.catch((e) => {
// The transaction will be rolled back, now handle the error.
console.log(e)
})
.finally(() => {
session.close()
driver.close()
})
}
const parseQuery = (result) => {
try {
const test = parser.parse(result)
console.log(test)
} catch (err) {
console.log(err)
}
}
module.exports = {
someQuery,
}
It finally clicked with me. Here is the solution I came up with. Hopefully it will help others. If there is a better way please let me know. Thank you #fbiville for you help.
async actions
const neo4j = require('neo4j-driver')
var parser = require('parse-neo4j')
const astria_queries = require('./astriaQueries')
const uri = 'bolt://astria_graph:7687'
const user = 'neo4j'
const password = 'neo'
async function getRecords(query) {
// run statement in a transaction
const driver = neo4j.driver(uri, neo4j.auth.basic(user, password))
const session = driver.session({ defaultAccessMode: neo4j.session.READ })
const tx = session.beginTransaction()
try {
const records = await tx.run(query)
const parseRecords = await parseQuery(records)
return parseRecords
} catch (error) {
console.log(error)
} finally {
session.close()
driver.close()
}
}
async function parseQuery(result) {
try {
const parsedRes = await parser.parse(result)
// console.log(parsedRes)
return parsedRes
} catch (err) {
console.log(err)
}
}
// getRecords(astria_queries.get_data_sources)
module.exports = {
getRecords,
}
api send()
exports.get_data_sources = async (req, res) => {
try {
queryFuns.getRecords(astria_queries.get_data_sources).then((response) => {
res.send(response)
})
} catch (error) {
res.status(500).send(error)
console.log(error)
}
}

AsyncStorage.getItem() doesn't seem to work

When I try to set a value via AsyncStorage.getItem(), I cannot request it back.
let tokenData = null;
const getData = async () => {
let token;
try {
token = await AsyncStorage.getItem('token');
tokenData = JSON.parse(token);
} catch (e) {
// error reading value
}
};
I have set item like follows
const setLoginLocal = async loginData => {
try {
let token = loginData.headers.authorization;
let headerToken = ['token', JSON.stringify(token)];
let user = ['user', JSON.stringify(loginData.data)];
await AsyncStorage.setItem([user, headerToken]);
} catch (err) {
console.log(err);
}
};
If you want to store data you have to setItem like this:
const storeData = async (key, value) => {
try {
await AsyncStorage.setItem(key, value);
} catch (error) {
console.log(error);
}
};
then you can retrieve it with getItem like this:
const getData = async key => {
try {
const data = await AsyncStorage.getItem(key);
if (data !== null) {
console.log(data);
return data;
}
} catch (error) {
console.log(error);
}
};
const setLoginLocal = async loginData => {
try {
let token = loginData.headers.authorization;
let headerToken = ['token', JSON.stringify(token)];
let user = ['user', JSON.stringify(loginData.data)];
await AsyncStorage.setItem([user, headerToken]);
} catch (err) {
console.log(err);
}
};

How to get the result of async / await function?

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

Getting all elements on the page with javascript

I wrote a web page crawler that successfully crawls a web page and grabs the data of one job posting using puppeteer. I'm now trying to get all the elements on the page with the class of .opportunity and then pass it into a function that will get the data for that specific job posting. However the list of getElementsByClassName is returning an empty object?
const puppeteer = require('puppeteer');
const fs = require('fs');
async function crawlOpo(opo) {
const opportunity = {
title: '',
desc: '',
category: '',
reqName: '',
hours: '',
postingDate: '',
locationName: '',
address: ''
};
const title = await page.evaluate(() => {
try {
return opo.querySelector('.row .col-lg-20 h3 a').innerText
} catch(err) {
return err
}
});
const desc = await page.evaluate(() => {
try {
return opo.querySelector('.hidden-xs.paragraph').innerText
} catch(err) {
return err
}
});
const category = await page.evaluate(() => {
try {
return opo.querySelector('.row.paragraph .col-sm-18 .row .col-md-8 .label-with-icon span').innerText
} catch(err) {
return err
}
});
const reqName = await page.evaluate(() => {
try {
return opo.querySelector('.row.paragraph .col-sm-18 .row .col-md-8:nth-of-type(2) .label-with-icon span').innerText
} catch(err) {
return err
}
});
const hours = await page.evaluate(() => {
try {
return opo.querySelector('.row.paragraph .col-sm-18 .row .col-md-8:nth-of-type(3) .label-with-icon span').innerText
} catch(err) {
return err
}
});
const postingDate = await page.evaluate(() => {
try {
return opo.querySelector('.row .col-lg-4 h3 small').innerText
} catch(err) {
return err
}
});
const locationName = await page.evaluate(() => {
try {
return opo.querySelector('.row.paragraph:nth-of-type(2) .col-lg-20 div div candidate-physical-location address span:nth-of-type(2) span').innerText
} catch(err) {
return err
}
});
opportunity.title = title;
opportunity.desc = desc;
opportunity.category = category;
opportunity.reqName = reqName;
opportunity.hours = hours;
opportunity.postingDate = postingDate;
opportunity.locationName = locationName;
opportunities.push(opportunity)
console.log(opportunities);
browser.close();
}
(async () => {
try {
const browser = await puppeteer.launch();
const page = await browser.newPage();
const opportunities = [];
let url = "https://recruiting2.ultipro.com/PUB1004PSCU/JobBoard/d433f5c3-37c8-4bcf-a3af-248a707c7d31/?q=&o=postedDateDesc"
await page.goto(url, {timeout: 0, waitUntil: 'networkidle0'});
const oportunitiesDOM = await page.evaluate(() => {
return document.getElementsByClassName('opportunity');
});
oportunitiesDOM.forEach(opo => {
await crawlOpo(opo)
});
} catch (err) {
console.error(err)
}
})()
The logic here is that it runs an async arrow function that will launch a browser -> load the page -> evalaute the page -> grab all the elements with the class .opporuntity -> loop over list and pass each opportunity into the crawlOpo function and then grab the specific data needed for that opportunity and then assign that object to an array.
In the argument of document.getElementsByClassName('.opportunity'), you have the CSS selector '.opportunity'.
The getElementsByClassName method takes a name of a class as an argument, not a CSS selector.
Most likely it should be corrected to document.getElementsByClassName('opportunity').

Categories

Resources