I'm facing a probably super easy to solve problem regarding fetching.
I'd like to fetch some json datas and store it in a variable to access it later.
The problem is that I always ends up getting undefined in my variable. What's the way to do to deal with that kind of data storing ?
Here's my code.
const fetchCities = () => {
fetch('cities.json')
.then(response => response.json())
.then(data => {
return data;
});
}
let cities = fetchCities();
console.log(cities)
Already looked up for answers but couldn't find a way to do. Thanks !
You could do this very simply with async/await like this:
const fetchCities = async () => {
let cities = await fetch('cities.json');
return cities.json();
};
let cities = await fetchCities();
console.log(cities);
Sending a fetch request takes time, so the console.log works before the data arrives.
The best way to deal with fetch is using async functions and await like so:
const fetchCities = ()=>{
return fetch('cities.json');
}
async function main(){
try {
const res = await fetchCities();
const data = await res.json();
// handle the data here, this will work only after the data arrival
console.log(data);
} catch (err) {
console.log(err);
}
}
main();
Note: await can only be used in async functions, that's the main purpose of the main function.
Or if you want to use .then:
const fetchCities = ()=>{
return fetch('cities.json');
}
function main(){
fetchCities()
.then(res => res.json())
.then(data => {
// handle the data here, all you code should be here
})
.catch (err => console.log(err));
}
main();
Related
I am using an open-source api to retrieve breweries when people search by city name. I can console. log the promise returned but when I try to loop and console.log the data it tells me undefined.
const searchBtn = document.getElementById('beer-search-button');
const getBeerData = (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${cityName}`;
encodeURI(beerApi);
fetch(beerApi)
.then(res => {
if(res.ok) {
console.log(res.json());
for(let b in res) {
console.log(b.name);
}
} else {
console.log('Error!');
}
});
}
searchBtn.addEventListener('click', function(e) {
e.preventDefault;
let searchQuery = document.getElementById('city-input').value;
getBeerData(searchQuery);
});
You need to loop over the result of res.json(). You do this with another .then().
And calling encodeURI() without using the result has no effect. You should be calling encodeURIComponent() on the city name, and using that in the URI.
const getBeerData = (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${encodeURIComponent(cityName)}`;
fetch(beerApi)
.then(res => {
if (res.ok) {
return res.json()
} else {
throw "Error";
}
}).then(res => res.forEach(b => console.log(b.name)));
}
You've logged the promise but you haven't parsed that JSON. You can't loop over an array if it doesn't exist. And, because it's an array you should be using a for/of loop for (const b of data)....
Here's a shortened version.
// Get the data
fetch(beerApi)
// Parse the data
.then(res => res.json())
// Loop over the data
.then(data => {
for (const b of data) {
console.log(b.name);
}
});
});
res.json() also returns a Promise which you need to await either using then() or using await which is certainly my preferred option.
Please note that there is no need to URL encode the whole string as the API's URL is already encoded correctly, so you just need to URI encode the city name. Another thing you should probably do, is wait for the DOM to be loaded using DOMContentLoaded event before assigning event listeners as otherwise problems could occur because the DOM element might not yet be present.
const getBeerData = async (cityName) => {
const beerApi = `https://api.openbrewerydb.org/breweries?by_city=${encodeURIComponent(cityName)}`;
const res = await fetch(beerApi);
if (res.ok) {
const breweries = await res.json();
breweries.forEach(brewery => console.log(brewery));
} else {
console.log("Error!");
}
};
window.addEventListener("DOMContentLoaded", event => {
const searchBtn = document.getElementById("beer-search-button");
searchBtn.addEventListener("click", async function (e) {
e.preventDefault;
let searchQuery = document.getElementById("city-input").value;
await getBeerData(searchQuery);
});
})
<input type="text" id="city-input" name="city-input">
<button id="beer-search-button">Search for breweries!</button>
I've trying to retrieve the data, but I can't return it, can only see it in the console,
it's a simple axios get function but for some reason, I keep getting Promise even after using async/await.
my goal is to save the data to the memory.
any help would really be appreciated
let fetchTodo = async () => {
await axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(res.data))
.then(res => { return res })
.catch(err => console.log(err))
};
console.log("TEST: ", fetchTodo())
console
Asycn function always returns a promise, to get data from the fetchTodo function you need to create another async function which will await the result returned by fetchTodo(). if you are using react, you can use states and update the state while you are inside the .then chain of the fetchTodo function.
Asycn function always returns a promise. For getting or saving data you need to get it from .then() function. Here you can check the example. Hope so it will help you.
let fetchTodo = async () => {
await axios.get('https://jsonplaceholder.typicode.com/todos/1')
.then(res => console.log(res.data))
.then(res => {
// here you can performance your task, save data, send
// response or anything else
return res
})
.catch(err => console.log(err))
};
fetchTodo()
The async/await syntax means a function will return a Promise.
If you want to return the value, you could do something like this:
let fetchTodo = async () => {
try {
const res = await axios.get("https://jsonplaceholder.typicode.com/todos/1");
return res;
} catch (error) {
console.log(error);
}
};
// For the folowing code to work, it must be placed inside a async function as well
const res = await fetchTodo();
console.log(`Test: ${res.data}`);
// If it's a Top level call, use the folowing code
const res = fetchTodo().then( res => {
const data = res.data;
// The rest of your code goes here.
// ...
// ...
// ...
}).catch( error => {
console.log(error);
});
Some more information about it on: How can I use async/await at the top level?
I am using node-fetch npm package to receive data using a specific API. In the code, I have written a forEach loop to fetch API response of every single element of the array (in my example the array is rows). But finally whenever I am returning the array and printing, the array showing a blank result ([]). I am new to NodeJS. Please help me with this problem.
What I want: An array of response (dataArr);
async function accessSpreadsheet(cl) {
await doc.useServiceAccountAuth({
client_email: creds.client_email,
private_key: creds.private_key,
});
await doc.loadInfo();
const title='Sheet4';
const rows = await getSheetByTitle(title);
//const array_size=rows.length;
//console.log(rows[0].keyword);
const dataArr=[];
const obj = new Promise((resolve,reject)=>{
rows.forEach(async (row) => {
var data=row.keyword;
fetch("https://api.url.com/")
.then(res => res.text())
.then(function(res) {
dataArr.push(res);
})
.catch(err => console.log(err));
});
console.log(dataArr);
});
// return dataArr;
}
You are printing the value of the array before it is getting populated.
Try this.
Promise.all(
rows.map(row =>
fetch(row)
.then(res => res.text())
.then(res => dataArr.push(res))
)
).then(() => console.log(dataArr));
The major issue with your code is forEach. Each of the async callback function calls does return a promise, but you're throwing them away instead of awaiting them. As a rule of thumb, use forEach for synchronous operations only.
Here's what you can do with Promise.all([...])
try {
const dataArr = await Promise.all(rows.map(async row => fetch(<your url>))
} catch (err) {
console.error(err)
}
I wonder if there is a way to access data from then on the next one? Code looks like this:
fetch(`http://localhost:3003/users/${userObject.id}`)
.then(res => res.json())
.then(user => {
...
})
.then(???)
and in second then I have all the needed info about the user. When I put everything in second then it works, but code is very messy and repetitive and I would like to put some things into function. Unfortunately, in that case, I don't have access to some data...
Any ideas? Thanks!
You can pass an argument to the next promise by returning it from the previous one.
fetch(`http://localhost:3003/users/${userObject.id}`)
.then(res => res.json())
.then(user => {
return user.id;
})
.then(userId => {
console.log('user id is:', userId);
});
Also, you can accomplish same result by using async programming like bellow:
async function fetchSomeData() {
var res = await fetch(`http://localhost:3003/users/${userObject.id}`);
var user = await res.json();
return user;
}
fetchSomeData().then(user => {
console.log('user id is:', user.id)
});
but code is very messy and repetitive and I would like to put some
things into function
Just use async/await syntax, it's much more understandable.
(async() => {
const request = await fetch(`http://localhost:3003/users/${userObject.id}`);
const result = await request.json();
// proceed to do whatever you want with the object....
})();
This is a self-executing function, but you can also declare this in the following way:
const myFunc = async() => {
const request = await fetch(`http://localhost:3003/users/${userObject.id}`);
const result = await request.json();
// your logic here or you can return the result object instead;
};
or even without arrow functions:
const myFunc = async function() {
const request = await fetch(`http://localhost:3003/users/${userObject.id}`);
const result = await request.json();
console.log(result.id);
};
getStore().then((store) => {
buildRates().then((rates) => {
let newStore = store;
newStore.rates = rates;
setStore(newStore).then((res) => {
// callback
cb(null, res);
})
})
});
Having trouble writing this in async/await syntax. When I try to write with awaits like this ...
let store = await getStore();
store.rates = await buildRates();
setStore(store).then((res) => {
// callback
cb(null, res);
});
... setStore uses the original object returned from await getStore(), without an object on store.rates from await buildRates()
Any ideas?
Solved. The issue was buildRates() not being a proper promises, oops!