Array of fetched items doesn`t show after data is fetched - javascript

I have this code:
const fetchPokemonData = async () => {
const data = await fetch('https://pokeapi.co/api/v2/pokemon?limit=151', options)
let pokemons = []
await data.json().then(pokemon => pokemons.push(pokemon.results))
return pokemons}
const getPokemonsUrl = async () => {
const pokemonsUrls = []
const pokemonData = await fetchPokemonData()
pokemonData[0].map(pokemons => pokemonsUrls.push(pokemons.url))
return pokemonsUrls}
const createPokemonObject = async () => {
const urls = await getPokemonsUrl()
const arrayOfPokemons = []
urls.map(async url =>{
const data = await fetch(url)
const pokemon = await data.json()
const { name, id, sprites: {other: {dream_world: {front_default}}}, types, weight, stats } = pokemon
arrayOfPokemons.push(
{
name: name,
id: id,
image: front_default, types: types,
weight: weight,
stats: stats
}
)
})
console.log(arrayOfPokemons) //works
arrayOfPokemons.map(pokemon => console.log(pokemon)) // works only after setTimeout() delay }
The problem is when I try to log each pokemon outside urls.map() array function, there is no each individual Pokemon, because the data isn`t fetched yet (I tested that put by putting arrayOfPokemons inside setTimeout() function and after some delay time, each Pokemon was shown). Can someone please rewrite or explain the way to rewrite this code do that I get all individual pokemons outside of urls.map() function, because that is the best way for me to learn.

There are several issues:
push returns the length of the array, not data. Instead of using push, really map the data with a .map and capture the returned array.
.map(async will execute the async callbacks immediately and continue. There is no waiting for those callbacks to terminate their asynchronous code. Either use a normal for loop or use await Promise.all
Here is a correction of your code:
const fetchPokemonData = async () => {
const data = await fetch('https://pokeapi.co/api/v2/pokemon?limit=151');
const pokemon = await data.json();
return pokemon.results;
}
const getPokemonsUrl = async () => {
const pokemons = await fetchPokemonData();
return pokemons.map(pokemon => pokemon.url);
}
const createPokemonObject = async () => {
console.log("wait for it...");
const urls = await getPokemonsUrl();
const arrayOfPokemons = await Promise.all(urls.map(async url => {
const data = await fetch(url);
const pokemon = await data.json();
const { name, id, sprites: {other: {dream_world: {front_default}}}, types, weight, stats } = pokemon;
return {
name: name,
id: id,
image: front_default, types: types,
weight: weight,
stats: stats
};
}));
console.log(arrayOfPokemons);
}
createPokemonObject();

Related

How to list and filter two request in one console

i'm trying to list my folders and subfolders but right now it only show me the folders not both
function getParserTypes (types, subject) {
return types.map((type) => {
return {
id: type.entry.id,
name: type.entry.name,
grade: subject.grade,
subject: subject.id
};
});
}
the first request call folders and with my second request call Subfolders
const firstRequest = await axios.get(`${fox.url}/nodes/${firstFolderId}/children`, PARAMS);
const secondRequest = await axios.get(`${fox.url}/nodes/${secondFolderId}/children`, PARAMS);
const types = _(firstRequest.data.list.entries).filter((type) => !type.entry.name.includes('dog'),
secondRequest.data.list.entries).filter((type) => !type.entry.name.includes('cat');
const resourcesTypes = getParserTypes(types, subject);
console.log("resourcesTypes",resourcesTypes)
my console display only my first Request not both
You are not awaiting both request. Since these are Promises, you can use Promise.all or Promise.allSettled. See this thread for difference. It returns a Promise too.
const res1 = await axios.get(
"https://jsonplaceholder.typicode.com/todos/1"
);
const res2 = await axios.get(
"https://jsonplaceholder.typicode.com/todos/2"
);
const res = await Promise.all([res1, res2]);
console.log(res);
-------- or --------------
Promise.all([res1, res2]).then((res) => {
console.log(res);
})

Reactjs problem rendering binary image retrieved from mongodb

Hello so I have images in a mongodb database and I'm trying to render them on the client side however It's not working. I convert the buffer unit8 data into base64 so I can render it it seemd to work and been stored in the images state but images are not accessible by associative array.
useEffect( () => {
const getAllDoctors = async () => {
const result = await api.get('doctor/all')
const myImages = []
setDoctors(result.data)
await result.data.forEach(async doctor => {
myImages[doctor._id] = await base64_arraybuffer(doctor.photo.data.data)
})
setImages(myImages)
setLoading(false)
}
getAllDoctors()
}, [])
as for the render
return (
<div>
{
images.map((image, key) => {
console.log(doctors)
return (
<div key={key}>
<img alt={'image'} src={`data:image/png; base64, ${image}`}/>
<div>{`Doctor + ${images}`}</div>
</div>
)
})
}
</div>
);
converter (not mine):
const base64_arraybuffer = async (data) => {
const base64url = await new Promise((r) => {
const reader = new FileReader()
reader.onload = () => r(reader.result)
reader.readAsDataURL(new Blob([data]))
})
return base64url.split(",", 2)[1]
}
Two things
The way your array assignment is doesn't make sense. If _id is a ID string, then you are using a string to key an array, the data assigned at that key won't be included in loops. Use Array.prototype.push to add the item to the next available index.
Array.prototype.forEach and async / await don't play nice together due to the nature of callbacks. Try using a traditional loop.
useEffect(() => {
const getAllDoctors = async () => {
const result = await api.get("doctor/all");
const myImages = [];
setDoctors(result.data);
for (const doctor of result.data) {
const image = await base64_arraybuffer(doctor.photo.data.data);
myImages.push(image)
}
setImages(myImages);
setLoading(false);
};
getAllDoctors();
}, []);

Using return data from an async function, in another function

I'm doing a little data analysis from chess.com data
I have this code
const getUsernames = async function() {
let response = await chessAPI.getCountryPlayers('RE')
names = [...response.body.players]
//console.log(names)
return names
}
const grabPlayerScores = async function() {
let players = getUsernames()
// let playerStats = [];
for (i = 0; i = players.length; i++) {
let data = await chessAPI.getPlayerStats(i)
console.log(data)
}
}
grabPlayerScores();
I can't get the other function to await the return of the first. I know I should use promises or structure my other function differently but I'm still getting the hang of these types of functions.
As a best practice, you should make sure all of your functions return a value. Use const for variables that will not change, and let for variables that you absolutely will change. Watch out for name = ... where you didn't write const or let, as this makes names into a global -
const getUsernames = async function() {
const response = await chessAPI.getCountryPlayers('RE')
return response.body.players // <- probably no need to copy
}
const grabPlayerScores = async function() {
const players = await getUsernames()
return Promise.all(players.map(p => chessAPI.getPlayerStats(p)))
}
Now grabPlayerScores will be a promise containing an array of all player scores -
grabPlayerScores().then(console.log).catch(console.error)
[ ..., ... ,... ]
Maybe you want the player data combined with the score data in the final output?
const grabPlayerScores = async function() {
const players = await getUsernames()
return Promise.all(players.map(async p => ({
player: p,
scores: await chessAPI.getPlayerStats(p)
})))
}
grabPlayerScores().then(console.log).catch(console.error)
[ { player: "alice", scores: ... },
{ player: "brenda", scores: ... },
{ player: "catherine", scores: ... } ]
Another good practice is to make your functions take parameters. This makes them more reusable in other areas of your program -
const getUsernames = async function(countryCode) {
const response = await chessAPI.getCountryPlayers(countryCode)
return response.body.players
}
const grabPlayerScores = async function(countryCode) {
const players = await getUsernames(countryCode)
return Promise.all(players.map(async p => ({
player: p,
scores: await chessAPI.getPlayerStats(p)
})))
}
Now you pass "RE" as an argument to your function, allowing you to easily reuse this function for other countries -
grabPlayerScores("RE").then(console.log).catch(console.error)
You need to add another await in your grabPlayerScores function to wait for getUsernames to finish.
const grabPlayerScores = async function() {
// Add an 'await' here
let players = await getUsernames();
for(let i = 0; i = players.length; i++) {
let data = await chessAPI.getPlayerStats(i)
console.log(data)
}
}
I changed bit in your code,
const grabPlayerScores = async function () {
let players = await getUsernames();
for (i = 0; i = players.length; i++) {
let data = await chessAPI.getPlayerStats(players[i]);
console.log(data)
}
}

Using promise.all on an array of axios requests is returning all of the responses in the last object instead of spreading them out

Each object should have around 250 arrays in it, but for some reason, each of the objects has a single array except for the last one, which has 1250.
How can I spread out the responses so I can access each one individually?
const [coinData, setCoinData] = useState();
const [loading, setLoading] = useState(true);
useEffect(() => {
createLocalStorage();
let existingLocalStorage = JSON.parse(localStorage.getItem('items'));
const fetchData = async () => {
const data = await Promise.all(
existingLocalStorage.map(obj =>
coinGecko.get(`/coins/${obj[0].coin}/market_chart/`, {
params: {
vs_currency: 'usd',
days: obj[0].time
}
}),
)
);
setCoinData(data);
setLoading(false);
};
fetchData();
}, []);
Here's the response:
response
I'm using create-react-app, and testing with console.log in the browser
I was sending the times as strings ('day', 'week', 'month', 'year', 'max') I totally forgot I needed to convert them to number values. Since max was the only acceptable parameter, that's the only one that returned the response I was looking for
Try calling your method like below-
import axios from 'axios';
useEffect(() => {
createLocalStorage();
let existingLocalStorage = JSON.parse(localStorage.getItem('charts'));
const fetchData = async () => {
await axios.all([api1, api2]).then(axios.spread((...responses) => {
const resp1 = responses[0]
const resp2 = responses[1]
// use the results
})).catch(errors => {
// errors.
})
}
fetchData();
}, []);

Firestore add return of function to database

I'm trying to create a function with firebase, where upon request the function carries out some scraping activites and then logs the result to a collection each time. My function works and returns the Array of items that I need, but I am having trouble then adding this array to the firestore database.
I am not sure if I need to subscribe to the response or if it is returning something else.
Cloud Function:
exports.scraper = functions.https.onRequest( async (request, response) => {
cors(request, response, async () => {
const body = (request.body);
const data = await scrapeteamtags(body.text);
response.send(data)
});
return admin.firestore().collection('games').add({
teams: data
})
});
Added the function used in the await for context:
const scrapeteamtags = (text) => {
const urls = Array.from( getUrls(text) );
const requests = urls.map(async url => {
const res = await fetch(url);
const html = await res.text();
const $ = cheerio.load(html);
const getTeamlist = JSON.parse($('body').text())
var gamelist = {
games: []
}
getTeamlist.SSResponse.children.map(function(item) {
// go into the returned json
var event = new Object;
var leagues = ["Premier League", "Spanish La Liga", "Italian Serie A", 'French Ligue 1', 'German Bundesliga']
// finds all child items that contain the event tag
if(Object.keys(item).includes('event')) {
// check that the league is on the list which are of interest
if(leagues.includes(item.event.typeName)) {
event.id = item.event.id;
event.name = item.event.name;
// add the event name and id to the object then go into next level to get market data
item.event.children.map(function(item1) {
if(Object.keys(item1).includes('market')) {
event.marketid = item1.market.id
// add the market data id to the object
var eventoutcome = []
item1.market.children.map(function(item2) {
if(Object.keys(item2).includes('outcome')) {
eventoutcome.push({"id" : item2.outcome.id,
"id": item2.outcome.id,
"name": item2.outcome.name,
"price": item2.outcome.children[0].price.priceDec})
//adds the id, name and price to an array, then add it to the object
event.outcome = eventoutcome
}
})
}
})
gamelist.games.push(event)
}
// push each event as a new object to the array of games
}
})
//console.log(gamelist.games)
return {
gamelist
}
});
return Promise.all(requests);
}
HTTP functions don't let you return a promise with the data to send. (That's how callable functions work, but that doesn't apply here.) You will have to wait for the database write to finish, then send the response to terminate the function.
The function should be structured more like this:
exports.scraper = functions.https.onRequest( async (request, response) => {
cors(request, response, async () => {
const body = (request.body);
const data = await scrapeteamtags(body.text);
await admin.firestore().collection('games').add({
teams: data
})
response.send(data)
});
});

Categories

Resources