Reputation: 331
I have an array of objects and I am iterating through the array with an async forEach loop and making an HTTP get request with Axios. I tell the compiler to wait for axios to finish before proceeding, but for some reason console.log(data) still runs before console.log(ret)
I think this might be because the forEach loop just gets skipped as soomn as it hits the await and continues, but I don't know how to fix this issue
data.forEach(async (e, i) => {
let req = `https://api.darksky.net/forecast/7e12d816d7818a03901fa6a72e6802f5/${e.lat},${e.log},${Math.floor(e.start_time / 1000)}?units=si`
let ret = await axios(req)
console.log(ret)
data[i]['weather'] = ret.data.currently.summary
data[i]['cloudCover'] = ret.data.currently.cloudCover
})
console.log(data)
Here is the output that I see (Note that the first array should theoretically have 'weather' and 'cloudCover' attributes, since they are appended)
[ { start_time: 1548952405372,
end_time: 1548953096266,
lat: 59.57644286,
log: 20.16817143 },
{ start_time: 1548958463054,
end_time: 1548959597889,
lat: 59.57644286,
log: 20.16817143 },
{ start_time: 1548964774667,
end_time: 1548966048587,
lat: 59.57644286,
log: 20.16817143 } ]
{ status: 200,
statusText: 'OK',
headers:
{ date: 'Wed, 10 Jul 2019 02:57:13 GMT',
'content-type': 'application/json; charset=utf-8',
'content-length': '10354',
connection: 'close',
'x-authentication-time': '705ms',
'x-forecast-api-calls': '13',
'cache-control': 'max-age=86400',
Upvotes: 2
Views: 4023
Reputation: 53598
forEach, in fact, doesn't wait for anything: you've given it an async
function so it can schedule a start call for that and immediately move on to the next function because there is nothing to wait for: as an async function, its return value is a Promise, not real data.
If you want to wait until all your async functions are done, then you'll have to use Promise.all
:
async runThisStuff() {
await Promise.all(data.map(async (e, i) => {
let url = `...`
let ret = await axios(url);
console.log(ret)
data[i]['weather'] = ret.data.currently.summary
data[i]['cloudCover'] = ret.data.currently.cloudCover
});
console.log(data);
}
And if you want to do this in global context, you may not be able to await Promise.all
(older browsers, Node, etc. can only await
inside an async
function), and you'll have to use the older then
that Promises offer:
Promise.all(
data.map(async(...) => { ... })
).then(() => {
console.log(data)
});
Upvotes: 6
Reputation:
you can use for of:
const foo = async () => {
const arr = [1,2,3,4,5,6];
for (let i of arr) {
const response = await // async operations
}
}
foo();
Upvotes: 0
Reputation: 59
forEach is actually synchronous. It takes a callback function as parameter, which in this case is your ASYNC function. So strictly speaking, all the codes were executed but at a different time than you expected them to. None was skipped.
Async/await is just syntactic sugar for Promise. That means that every line of code after "await" in your loop is only executed when the promised is resolved.
A better way to do this could be promise.All() like others have suggested.
Upvotes: 0
Reputation: 23778
The forEach
method makes multiple function calls without waiting for anything regardless of what goes on inside these functions.
The flow inside the functions are effected by await
- but forEach
itself is not.
Use for-in loop for synchronous remote requests.
async function makeCalls() {
console.log('starting');
for (d in data) {
let req = `https://api.darksky.net/forecast/7e12d816d7818a03901fa6a72e6802f5/${e.lat},${e.log},${Math.floor(e.start_time / 1000)}?units=si`
let ret = await axios(req)
console.log(ret)
d['weather'] = ret.data.currently.summary
d['cloudCover'] = ret.data.currently.cloudCover
}
console.log('ending');
}
Upvotes: 0
Reputation: 56
All you need to do is using Promise.all
and Array.map
. it will wait all promises to be done. see below.
const newData = await Promise.all(data.map(async(e, i) => {
let req = `https://api.darksky.net/forecast/7e12d816d7818a03901fa6a72e6802f5/${e.lat},${e.log},${Math.floor(e.start_time / 1000)}?units=si`;
let ret = await axios(req);
console.log(ret);
e.weather = ret.data.currently.summary;
e.cloudCover = ret.data.currently.cloudCover;
return e;
}));
console.log(newData);
Upvotes: 0