how to get only data from fetch [duplicate] - javascript

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 5 months ago.
I try to get only the data of my fetch request but when i go out of my function there is a promise arround.
I try to fetch an API for starting a store in svelteJS but I'm wrong.
import {writable} from "svelte/store";
const getPokedex = async function () {
let pokedexData
await fetch('https://pokeapi.co/api/v2/pokemon?limit=100&offset=0')
.then(response => response.json())
.then(data => {
pokedexData = createPokedex(data)
})
return pokedexData
}
const createPokedex = function (data) {
let pokedex = writable(data)
...
}
export const pokedex = getPokedex();
SOLVED:
const getPokedex = async () => {
const response = await fetch('https://pokeapi.co/api/v2/pokemon?limit=100&offset=0');
const data = await response.json();
let pokedex = data.results
return createPokedex(pokedex);
}
export const pokedexStore = await getPokedex();

Make use of async/await and try to not use then/catch while using async/await this will make your code more clean, readable, easy to work with
const getPokedex = async function () {
const response = await fetch("https://pokeapi.co/api/v2/pokemon?limit=100&offset=0");
const data = await response.json();
return createPokedex(data);
};
this code will return the data you just have to wait for the promise using await
const pokedex = await getPokedex();

Related

How to escape this callback hell

I'm currently trying to fetch data from public API about a country and its neighboring countries to render on my html.
renderCountry( ) is a function to implement on my html with the data I will receive.
I also excluded some unnecessary codes, which I believe is not major in this particular case.
This is how I fetch data:
const getCountryAndNeighbour = function(country) {
fetch(`https://restcountries.com/v2/name/${country}`)
.then(response => response.json())
.then(data => {
renderCountry(data[0]);
const neighbour = data[0].borders;
neighbour.forEach(country => {
fetch(`https://restcountries.com/v2/alpha/${country}`)
.then(response => response.json())
.then(data => renderCountry(data, `neighbour`))
});
})
}
Here, you will see callback hell architecture. Any idea for escape from that?
Thanks in advance.
You can try using async/await. You would add async before the function keyword and add await as needed. See below to see this in action:
const getCountryAndNeighbour = async function (country) {
const res = await fetch(`https://restcountries.com/v2/name/${country}`)
const data = await res.json();
renderCountry(data[0]);
const neighbour = data[0].borders;
await Promise.all(
neighbour.map(async country => {
let response = await fetch(`https://restcountries.com/v2/alpha/${country}`)
response = await response.json();
return renderCountry(response, 'neighbour');
});
);
}
You can rewrite it using async/await
eg.
const getCountryAndNeighbour = async country => {
const response = await fetch(`https://restcountries.com/v2/name/${country}`);
const data = await response.json();
renderCountry(data[0]);
const neighbour = data[0].borders;
neighbour.forEach(async country => {
const response = await fetch(`https://restcountries.com/v2/alpha/${country}`)
const data = await response.json();
renderCountry(data, `neighbour`);
});
};
Please note that forEach will run all promises in the same time.
If you want to run one by one you should use eg. for loop or some util like Bluebird.map which allows you to specify a concurrency
Good luck!
This will do using Async/await
async function getCountryData(country) {
const response = await fetch(`https://restcountries.com/v2/name/${country}`);
return await response.json();
}
async function getNeighbourData(country) {
const response = await fetch(`https://restcountries.com/v2/alpha/${country}`);
return await response.json();
}
async function getCountryAndNeighbour(country) {
const data = await getCountryData(country);
const neighbourCountries = data[1].borders;
for (const neighbour of neighbourCountries) {
const response = await getNeighbourData(neighbour);
console.log(response);
}
}
Add the necessary validations when checking [0]/[1] in your function.

making api requests and response.json()

I have a question about api request and async await
For example, I have a function as such:
export const getTopStories = async () => {
const response = await instance.get(`/home.json?api-key=${api_key}`)
const data = response.json()
return data
}
is response.json() completely necessary here? I think I've also seen it where data is destructured immediately, for example,
export const getTopStories = async () => {
const {data} = await instance.get(`/home.json?api-key=${api_key}`)
return data
}
Does the second version work? Are they equivalent somehow?

my async funtion is returning Pending even if im using .then [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
That my Code trying to returning response.data.
const getRobots = () => {
axios.get("https://jsonplaceholder.typicode.com/users").then((response) => {
return response.data;
});
};
let robotsValue = getRobots();
console.log(robotsValue);
Pending
You need to use the then after you call the function, not inside it. I changed it to fetch so i could show you in a snippet.
const getRobotsThen = () => {
return fetch("https://jsonplaceholder.typicode.com/users");
};
getRobotsThen()
.then(res => res.json())
.then(data => console.log(data));
Another option is to use the async await combo
const getRobotsAsync = async () => {
const res = await fetch("https://jsonplaceholder.typicode.com/users");
return await res.json();
}
// await only works in an async function, thats why there is an IIFE
(async () => {
let robotsValueAsync = await getRobotsAsync();
console.log(robotsValueAsync);
})()

"Exit promise" with multiples fetch requests

I need to merge data from API. I do a first call to an endpoint that gives me a list of ids, then I do a request for each id. My goal is to return a list with the responses of all requests but I lost myself in promises ...
My code runs on NodeJS. Here is the code :
const fetch = require('node-fetch')
const main = (req, res) => {
fetch('ENDPOINT_THAT_GIVES_LIST_OF_IDS')
.then(response => response.json())
.then(response => {
parseIds(response)
.then(data => {
console.log(data)
res.json(data)
// I want data contains the list of responses
})
})
.catch(error => console.error(error))
}
const getAdditionalInformations = async function(id) {
let response = await fetch('CUSTOM_URL&q='+id, {
method: 'GET',
});
response = await response.json();
return response
}
const parseIds = (async raw_ids=> {
let ids= []
raw_ids.forEach(function(raw_id) {
let informations = {
// Object with data from the first request
}
let additionalInformations = await
getAdditionalInformations(raw_id['id'])
let merged = {...informations, ...additionalInformations}
ids.push(merged)
})
return ids
})
main()
I get this error : "await is only valid in async function" for this line :
let additionalInformations = await getAdditionalInformations(raw_id['id'])
Help me with promise and async/await please.
You're almost there, just a slight bit of error here with your parentheses:
// notice the parentheses'
const parseIds = async (raw_ids) => {
let ids= []
raw_ids.forEach(function(raw_id) {
let informations = {
// Object with data from the first request
}
let additionalInformations = await getAdditionalInformations(raw_id['id'])
let merged = {...informations, ...additionalInformations}
ids.push(merged)
})
return ids
}
You are missing an async after forEach
const parseIds = (async raw_ids=> {
let ids= []
raw_ids.forEach(async function(raw_id) {
let informations = {
// Object with data from the first request
}
let additionalInformations = await
getAdditionalInformations(raw_id['id'])
let merged = {...informations, ...additionalInformations}
ids.push(merged)
})
return ids
})
One suggestion: you are mixing promises (.then()) with async/await. Prefer async/await is more readable.
Note that getAdditionalInformations inside forEach doesn't wait for it to be done before going to the next entry of the array.
You can use plain old for(var i=0; .... instead

JS return doesn't wait for await [duplicate]

This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 4 years ago.
I am trying to use the async await.
My app starts like this
axios.get(`${ROOT_URL}/ccidxann.php`)
.catch(err => console.error('axios error get', err))
.then(async res => {
const html = res.data
const jobList = await getJobList(html)
console.log(' after each jobList', jobList)
// jsonfile.writeFileSync('jobs.json', jobList, { flag: 'a' })
})
.catch(err => console.error(err))
The problem is that jobList is always returned as an empty array.
Here is the getJobList function
async function getJobList (html) {
const jobList = []
const dom = new JSDOM(html)
const { window } = dom
const $ = require('jquery')(window)
const jobsInDom = $('table').first().find('td > a')
// AWAIT HERE
await jobsInDom.each(async function (index, jobElem) {
const name = $(jobElem).text()
const url = $(jobElem).attr('href')
// Another AWAIT HERE
const jobDetailsHTML = await getJobDetailsHTML(`${ROOT_URL}/${url}`)
.catch(err => console.error('getJobDetailsHTML err', err))
const domDetails = new JSDOM(jobDetailsHTML)
const { window: windowDetails } = domDetails
const $details = require('jquery')(windowDetails)
const jobDetailsHTMLBody = $details('body').prop('outerHTML')
jobList.push({
_id: url,
name,
detailsHTML: jobDetailsHTMLBody
})
console.log('in each jobList', jobList)
}) //each
return jobList
}
As you can see I put the async keyword in front of it,
and I have put the async keyword in the callback of each
and put await in front of all async operations.
The console.log in the callback of each prints the array filled with values
but it seems the return works before the each
even with await keyword in front of it.
And also here is getJobDetailsHTML just in case. It's a simple function and seems to work just fine
async function getJobDetailsHTML (url) {
// ANOTHER AWAIT HERE
return await axios.get(url).data
}
I think jobsInDom.each is synchronous function, so putting await before doesn't give you desired effect. So somehow you need to get promise which resolved when processing is finished for all jobs, like this:
// handles one element and returns promise
const jobHandler = async jobElem => {
const name = $(jobElem).text()
const url = $(jobElem).attr('href')
const jobDetailsHTML = await getJobDetailsHTML(`${ROOT_URL}/${url}`)
.catch(err => console.error('getJobDetailsHTML err', err))
const domDetails = new JSDOM(jobDetailsHTML)
const { window: windowDetails } = domDetails
const $details = require('jquery')(windowDetails)
const jobDetailsHTMLBody = $details('body').prop('outerHTML')
jobList.push({
_id: url,
name,
detailsHTML: jobDetailsHTMLBody
})
console.log('in each jobList', jobList)
}
const promises = [];
// start processing of each element
jobsInDom.each((index, jobElem) => promises.push(jobHandler(jobElem));
// wait for processing of all job elements
await Promise.all(promises);

Categories