loadData() returning empty array - javascript

I'm trying to return an array of objects to a function, and looking at the debugger, it looks like it just returns an empty array.
Here's the function that I'm hoping to use:
// load from json file
loadData(filepath) {
let rooms = [];
fetch(filepath)
.then(
res => res.json()
)
.then(function (data) {
// console.log(data);
for (let i = 0; i < data.rooms.length; i++) {
rooms.push(data.rooms[i]);
}
});
return rooms;
}
I go into the debugger, and I see the rooms from data.rooms getting pushed to my local rooms object, but when I get back up to my init() function that's supposed to use this rooms data:
let rooms = this.loadData(this.datapath); // TODO: make games load from json data
for (let i = 0; i < rooms.length; i++) {
this.addRoom(rooms[i].name, rooms[i].getText, rooms[i].prompts, rooms[i].requirements);
}
It looks like it's passed an empty array. Is there a scoping issue or something I'm missing? I'm not very experienced with fetch/promises/JSON.
Happy to provide any further info that may be useful. Thanks!

The problem is that your local variable rooms will be returned before the async fetch finish.
You can just simple await the fetch statements and make the function async:
async loadData(filepath) {
let rooms = [];
const response = await fetch(filepath);
const data = await response.json();
console.log(data);
for (let i = 0; i < data.rooms.length; i++) {
rooms.push(data.rooms[i]);
}
return rooms;
}
let rooms = await this.loadData(this.datapath);

Try this, if it did not work let me know.
// load from json file
async function call() {
const loadData = async filepath => {
let rooms = [];
return await fetch(filepath)
.then(res => res.json())
.then(async data => {
rooms = await [...data];
return rooms;
});
};
let x = await loadData("https://jsonplaceholder.typicode.com/posts");
console.log("TEST: ", x);
}
call();

Related

loop async calls in for loop and console the data after for loop

data is coming as a blank Array [] whereas I was expecting data to be like an Array of object. If I tried setTimeout(() => {console.log(data)}, 1000) then it is console the data properly, but I don't want to use setTimeout() to console data in synchronous manner.
let data = [];
for(let i=1; i<11; i++) {
const url = `https://jsonplaceholder.typicode.com/todos/` + i;
(async () => {
let response = await fetch(url);
let resJson = await response.json();
data.push(resJson);
})();
}
console.log(data);
/*
* Working but don't want to use this
setTimeout(() => {console.log(data)}, 1000);
*/
That console.log(data) part of the code is not going to wait for the async block to be resolved and instead will be executed synchronously. Instead you could first push requests to one array and then resolve them with Promise.all and do all of that inside of IIFE.
(async() => {
let requests = [];
for (let i = 1; i < 11; i++) {
requests.push(fetch(`https://jsonplaceholder.typicode.com/todos/${i}`));
}
const responses = await Promise.all(requests)
const data = await Promise.all(responses.map(res => res.json()))
console.log(data)
})();

Array pushes data fetched from an api twice

I'm making a call to an api and I'm using async/await. I'm pushing the response data to a global array, but for some reason it is pushing it twice. I'm making two fetch requests, receiving the response, pushing it to an array, and then console logging the data array. How can I prevent it from pushing the data to the array twice?
var data = [];
const getData = async () => {
const f1_data = await fetch(url + countryOne.value)
.then(response => response.json())
.then((result) => {
var index = result.length - 1;
var confirmed = result[index].Confirmed;
textOne.textContent = result[index].CountryCode + " TOTAL CASES : " + confirmed;
data.push(confirmed);
console.log(data);
})
const f2_data = await fetch(url + countryTwo.value)
.then(response => response.json())
.then((result) => {
var index = result.length - 1;
var confirmed = result[index].Confirmed;
textTwo.textContent = result[index].CountryCode + " TOTAL CASES : " + confirmed;
data.push(confirmed);
console.log(data);
})
};
getData();
Expected output
Example: 56789, 89768
Output
56789, 56789, 89768, 89768
As other suggested, since you are using aysnc and await, might as well get rid of the .then() flow.
It seems like your getData() has been called multiple times, it is unsafe to keep data array outside of your getData function block. You might want to do something like this: (takes few seconds to get the api data..)
const getData = async () => {
const url = 'https://api.covid19api.com/country/'
const query = '?from=2020-12-31T00:00:00Z&to=2021-01-01T00:00:00Z';
let data = [];
const f1_data = await fetch(`${url}singapore${query}`);
const f1_json = await f1_data.json();
data.push(f1_json[0].Confirmed);
const f2_data = await fetch(`${url}malaysia${query}`);
const f2_json = await f2_data.json();
data.push(f2_json[0].Confirmed);
return data;
};
const logData = async () => {
let data = await getData();
console.log(data);
}
logData();
return the data from your async getData function.

How to change variable value in Axios response?

I'm trying to change a variable value in axios's then. Here is my example:
var pts = [];
axios.get('http://www.example.com')
.then(function (response) {
pts = response.data;
});
console.log(pts);
The pts variable just returns empty array. I just want to use it out of the GET query. How can I change it?
use the new elegant way async & await it is more neat and readable
let pts = [];
const getData = async () => {
const {data} = await axios.get("http://www.example.com");
pts = data;
return data
}
getData();
console.log(pts);
The request is asynchronous so the pts gets printed first and then the function gets called
What you can do is use a promise and make your request as follows:
const func1 = () => {
return axios.get("http://www.example.com").then(response => {return response})
}
func1().then(data => {
pts = data;
})

How to use promises so that loop doesn't hang

I am trying to loop through records in a database, in order to compile an array (cardsToInsert) that I will write to another database.
I was getting stuck because the array was writing to the database before the loop finished, I know I need to use promises / async functions to achieve what I want, but I'm pretty sure I'm doing something wrong with my promises.
The code works for a few loops (it goes for about 6-10 loops, it's supposed to loop 16 times), but then hangs while trying during wixData.get (or it hangs on a different promise that is part of buildCard).
// wixData.get is a function that returns a promise
async function loopCards(cardsToGet) {
let writeCard
let buildCard
for (let index = 0; index < cardsToGet.length; index++) {
const cardToGet = cardsToGet[index].card
buildCard = await wixData.get("Card", cardToGet)
.then((card) => {
return card
})
.catch((err) => {
let errorMsg = err;
return errorMsg
});
writeCard = await buildingCard(buildCard)
cardsToInsert.push(writeCard)
}
return cardsToInsert
}
What am I doing wrong? (or what is the key thing I'm doing wrong that is stopping this working, I'm sure there is plenty to be improved here!)
UPDATE
I've now updated the code and it loops through fine.
async function loopCards(cardsToGet) {
console.log('Start')
let writeCard
let buildCard
for (let index = 0; index < cardsToGet.length; index++) {
const cardToGet = cardsToGet[index].card
buildCard = wixData.get("Card", cardToGet)
.then(async (card) => {
writeCard = await buildingCard(card)
cardsToInsert.push(writeCard)
})
.catch((err) => {
let errorMsg = err;
return errorMsg
});
}
return cardsToInsert
}
How do I get it to wait for the loop to finish before finally returning cardsToInsert?
Your mix of async/await and .then is not really best practice
This should work, and will return once cardsToInsert is populated
async function loopCards(cardsToGet) {
const cardsToInsert = [];
for (let cardToGet of cardsToGet) {
try {
const card = await wixData.get("Card", cardToGet);
const writeCard = await buildingCard(card);
cardsToInsert.push(writeCard);
}
catch(err) {
let errorMsg = err;
return errorMsg;
}
}
return cardsToInsert;
}
better still, you really don't need to handle any errors here, since the calling function could do that
So it becomes even simpler
async function loopCards(cardsToGet) {
const cardsToInsert = [];
for (let cardToGet of cardsToGet) {
const card = await wixData.get("Card", cardToGet);
const writeCard = await buildingCard(card);
cardsToInsert.push(writeCard);
}
return cardsToInsert;
}
then using it could be like
loopCards(cards)
.then(result => doSomethingWihtResult)
.catch(error => handleError);
or if calling from an async function
try {
let result = await loopCards(cards);
// do something with result
} catch(error) {
// handle Error
}

how to send requests inside loop to backend and use await and make the loop executes sequentially

I have an array list of sizes which i want to create in the database so i loop on the array and send a request for each item in the array using await to get the response , the problem is the async part takes too much time the loop continues execution and when it ends the method returns size_group with an empty array, also the array get filled after the return but the returned data is empty
add(body) {
let sizeGroup = null;
let sizes = null;
return god.post('/size_groups', body)
.then((response) => {
sizeGroup = response.data.size_group;
for (var i = 0; i < body.sizes.length; i++) {
let size = {
'name': body.sizes[i].label,
'size_group': sizeGroup._id
};
(async () => {
let response2 = await god.post('/sizes', size);
if (response2.data.status === true)
sizeGroup.push(response2.data.size);
})();
}
return sizeGroup;
});
}
This is one of few problems that async..await solves. Since async functions are supported in current environment, there's no reason to combine them with promise chains, the entire function should be converted to async:
async add(body) {
const response = await god.post('/size_groups', body)
let sizeGroup = response.data.size_group;
for (var i = 0; i < body.sizes.length; i++) {
let size = {
'name': body.sizes[i].label,
'size_group': sizeGroup._id
};
let response2 = await god.post('/sizes', size);
if (response2.data.status === true)
sizeGroup.push(response2.data.size);
}
return sizeGroup;
}

Categories