I am making 2 fetch requests. I want to convert the data to JSON and then set it to a variable.
async componentDidMount() {
Promise.all([
await fetch('/link1'),
await fetch('/link2'),
]).then(links => {
const response1 = links[0]
const response2 = links[1]
const res1 = response1.json()
const res2 = response2.json()
})
const data1 = res1.data
const data2 = res2.data
...
I'm not able to set data1 and data2 to the responses. I am new to this so I'm not sure how to format it. How do I set data1 and data2?
You can just do
let data = [];
Promise.all([fetch("/link1"), fetch("/link2")])
.then(responses =>
responses.forEach(res => res.json().then(body => data.push(body)))
)
.catch(err => console.error(err));
If you need access to those variables under render, it is common to store them in a state variable.
async componentDidMount() {
Promise.all([
await fetch('/link1'),
await fetch('/link2'),
]).then(links => {
const response1 = links[0]
const response2 = links[1]
const res1 = response1.json()
const res2 = response2.json()
this.setState({data1: res1.data, data2: res2.data})
})
Then use you can use data1 and data2 as this.state.data1/2
To understand why what you are doing is not working, you need to read more about how Promise works. (https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Promise)
The main reason is because JS is async, so the data1 and data2 are assigned at the same time as Promise.all is fired.
Here's how I would do multiple fetches.
Promise.all(
[
'https://jsonplaceholder.typicode.com/todos/1',
'https://jsonplaceholder.typicode.com/todos/2'
].map(url => fetch(url).then(r => r.json()))
).then(results => console.log(results))
Promise.all takes an array of promises and returns a new promise that is complete when all the provided promises have completed.
It's best to do the .json() work in the thenable chain (since the conversion to JSON is asynchronous as well as the fetch). And then just await the two final results.
The result of the Promise.all is an array of the results of each promise (in the same order you provided the promises to Promise.all -- doesn't matter which order they completed in.)
Don't use await and Promise both. You can try like this to get the expected output.
async componentDidMount() {
const link1Fetch = await fetch('/link1');
const link2Fetch = await fetch('/link2');
const data1 = await link1Fetch.json();
const data2 = await link2Fetch.json();
console.log(data1, data2);
}
Related
So I'm using the API of National Weather Service to create a weather app. But the fetched data is very complicated, and I need to fetch two different APIs. So I want to write a customized async function that returns a promise, which resolves to an object that contains only the necessary data I need.
I came up with something like this:
async function fetchWeatherAPI(){
//data that I need
let data = {};
try {
const res1 = await fetch(url1);
const result1 = await res1.json();
data = {...data , result1.usefulData};
} catch(error){}
try {
const res2 = await fetch(url2);
const result2 = await res2.json();
data = {...data, result2.usefulData};
} catch(error){}
return new Promise((resolve,reject)=>{
resolve(data);
})
}
This code is working for me. But the problem is, what if the APIs reject? How can I handle the error so that I can display the error message in the returned promise? I may want something like this:
return new Promise((resolve,reject)=>{
if(...) reject(errrorMessage);
resolve(data);
})
Just do return data. You're already inside an async function and the return value from that function will be the resolved value of the promise that the async function already returns:
async function fetchWeatherAPI(){
//data that I need
let data = {};
const res1 = await fetch(url1);
const result1 = await res1.json();
data = {...data , result1.usefulData};
const res2 = await fetch(url2);
const result2 = await res2.json();
data = {...data, result2.usefulData};
return data;
}
In addition, your catch blocks are silently eating errors and attempting to continue as if nothing went wrong. You probably just want the error to propagate back to the caller so if you just remove your try/catch blocks, that's what will happen.
And, the return new Promise() you have is entirely superfluous and unnecessary (referred to as an anti-pattern). You can just remove it and return data instead.
Note: Since the code you show does not show any dependency between your first and second fetch() calls, you could run them in parallel and perhaps finish them faster.
async function fetchWeatherAPI(){
//data that I need
let data = {};
const [result1, result2] = await Promise.all([
fetch(url1).then(r => r.json()),
fetch(url2).then(r => r.json())
]);
return {...data, result1.usefulData, result2.usefulData};
}
Or, I often use a helper function in my code when doing a lot of fetch() calls:
function fetchJson(...args) {
return fetch(...args).then(r => r.json());
}
async function fetchWeatherAPI() {
//data that I need
let data = {};
const [result1, result2] = await Promise.all([
fetchJson(url1),
fetchJson(url2)
]);
return { ...data, result1.usefulData, result2.usefulData };
}
I'm trying to use anonymous functions to get two datasets. using two fetch call the second call depending on the 1st and the second is a loop I Keep get a err on the second call response2.json is not a function
async function example() {
let response1 = await fetch(
`https://www.flickr.com/services/rest/?method=flickr.photos.search&api_key=9c348b767f7a0403e907b0788188afba&text=observatory&accuracy=+11&media=photos+&geo_context=1&lat=41.8989&lon=-87.6123&radius=25&radius_units=km&extras=&format=json&nojsoncallback=1`
);
let json = await response1.json();
console.log(json.photos.photo);
const response2 = await json.photos.photo.map((i) =>
fetch(
`https://www.flickr.com/services/rest/?method=flickr.photos.geo.getLocation&api_key=9c348b767f7a0403e907b0788188afba&photo_id=${i.id}&format=json&nojsoncallback=1`
)
);
const json2 = await response2.json();
console.log(json2);
return {
dataset1: json,
dataset2: json2
};
}
Issue
response2 is array of promises,
await json.photos.photo.map will not make inner request synchronous,
const response2 = await json.photos.photo.map((i) =>
fetch(
`https://www.flickr.com/services/rest/?method=flickr.photos.geo.getLocation&api_key=9c348b767f7a0403e907b0788188afba&photo_id=${i.id}&format=json&nojsoncallback=1`
)
);
Solution :
const promises = json.photos.photo.map((i) =>
fetch(
`https://www.flickr.com/services/rest/?method=flickr.photos.geo.getLocation&api_key=9c348b767f7a0403e907b0788188afba&photo_id=${i.id}&format=json&nojsoncallback=1`
)
));
// get all response from promises
const response2 = await Promise.all(promises)
// response2 is array of responses , so we need to loop through it
const json2 = await Promise.all(response2.map(res => res.json()));
const response2 = await json.photos.photo.map(fetch('yourUrl'))
Here what follows up await is an array, not a promise
So maybe you can use Promise.all to wrap up this array.
But fetch is a little special than common promise.
const response2 = await Promise.all(json.photos.photo.map(fetch('yourUrl')));
const responseVirtual = response2.map(res => res.json());
May it help you, bro
I am trying to combine two fetch requests in one call so I can get all the data in the same array.
I have tried the Promise.all method but I don't know if it is the right way to do it.
getWeather = async (e) => {
e.preventDefault();
const city = e.target.elements.city.value;
//const api_call = await
const promises = await Promise.all([
fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&APPID=${API_KEY}`),
fetch(`http://api.openweathermap.org/data/2.5/forecast?q=${city}&units=metric&APPID=${API_KEY}`)
])
const data = promises.then((results) =>
Promise.all(results.map(r => r.text())))
.then(console.log)
The code actually works and I'm getting data back but I can't understand the json response.
(2) ["{"coord":{"lon":-5.93,"lat":54.6},"weather":[{"id"…7086601},"id":2655984,"name":"Belfast","cod":200}", "{"cod":"200","message":0.0077,"cnt":40,"list":[{"d…on":-5.9301},"country":"GB","population":274770}}"]
How should I set the state?
My state was set like this, with only one call.
if (city) {
this.setState({
temperature: data[0].main.temp,
city: data[0].name,
Is there a better way to do it?
I'd do:
getWeather = async (e) => {
e.preventDefault();
const fetchText = url => fetch(url).then(r => r.json()); // 1
const /*2*/[weather, forecast] = /*3*/ await Promise.all([
fetchText(`.../weather`),
fetchText(`.../forecast`)
]);
this.setState({ temperature: weather.temp, /*...*/ });
}
1: By using a small helper, you don't have to call Promise.all twice. With this both requests are done in parallel (and you should use .json() as you want to parse it as JSON).
2: Through array destructuring you can easily get back the promises results.
3: Through awaiting you get the actual benefit from async functions: You don't need nested .then chains
You can write in following way which is cleaner approach and will have your data categorised
const success = res => res.ok ? res.json() : Promise.resolve({});
const weather = fetch(`http://api.openweathermap.org/data/2.5/weather?q=${city}&units=metric&APPID=${API_KEY}`)
.then(success);
const forecast = fetch(`http://api.openweathermap.org/data/2.5/forecast?q=${city}&units=metric&APPID=${API_KEY}`)
.then(success);
return Promise.all([weather, forecast])
.then(([weatherData, forecastData]) => {
const weatherRes = weatherData;
const ForecastRes = forecastData; // you can combine it or use it separately
})
.catch(err => console.error(err));
}
Do I need the awaits when inside a promise.all? What else can be wrong with this?
(async => {
const result = Promise.all(
await domainContext.get1(id),
await domainContext.get2(id)
).then(r => r);
})();
I'm expecting :
result = [get1_value, get2_value]
I'm getting :
'{}'
Promise.all expects an array as a single argument, not a list of Promises in its arguments. Also, if you're using Promise.all, don't await inside - that kind of defeats the purpose, because then you're passing an array of resolved values to Promise.all rather than passing it an array of Promises to wait for. Also, to define an async function with no parameters, you need to add an empty parameter list after the async:
const get1 = () => Promise.resolve('get1');
const get2 = () => Promise.resolve('get2');
(async () => {
const result = await Promise.all([
get1(),
get2(),
]);
console.log(result);
})();
You could also await each item in the result array, like this:
const get1 = () => Promise.resolve('get1');
const get2 = () => Promise.resolve('get2');
(async () => {
const result = [
await get1(),
await get2(),
];
console.log(result);
})();
which might have been what you were trying to do, but note that this results in each item being requested in serial, rather than in parallel.
I have two files that are arrays, and i want to load them from a fetch. I have an async function that fetch the files:
async function getData(file) {
const data = await fetch(`./assets/resources/${file}.json`);
return await data.json()
}
Then here is where i assign the variables to the return fo this fetch:
let notes = getData("notes").then(res => res)
let pentagrama = getData("pentagrama").then(res => res)
But with this all i get is:
from google chrome console
How can i actually get the value?
The result of getData is always a Promise that resolves to your data. To access the values, you can use async/await:
(async () => {
let notes = await getData("notes");
let pentagrama = await getData("pentagrama");
// use them here
})();
Alternatively, you can use Promise.all to wait for both promises to resolve, and then access the received data:
let notesP = getData("notes");
let pentagramaP = getData("pentagrama");
Promise.all([noteP, pentagramaP]).then(res => {
let notes = res[0];
let pentagrama = res[1];
// use them here
});
ASYNC
AWAIT
This will work for you if you just want to check the response in your Google Chrome console because in the console you can use await without an async function which probably could be because everything executed in the console is wrapped in an async function by default(just a speculation).
ONLY WORKS IN CONSOLE:
const getData = (file) => (
fetch(`./assets/resources/${file}.json`).then(data => data.json());
)
let notes = await getData("notes")
let pentagrama = await getData("pentagrama")
But if you want to get this working in an application, remember that you ALWAYS need to wrap an await inside async
TO GET IT WORKING IN AN APPLICATION:
const getData = async (file) => (
await fetch(`./assets/resources/${file}.json`).then(data => data.json());
)
const wrapperFunc = async () => {
let notes = await getData("notes")
let pentagrama = await getData("pentagrama")
}