'Function returning before data is processes [duplicate]
I thought for loops were blocking in Javascript, but this function is returning an empty array before the for loop finishes. Is the answer to this to setup a new function with just the for loop as a promise? If so what does that look like, the syntax for a promise is really confusing to me.
async function retrieve_s3_file(to_do_list, guid){
var data_list = [];
for (let i = 0; i < to_do_list.length; i++)
{
element = to_do_list[i];
console.log("\n\nOutgoing request /jobs/list?guid=" + guid + "&file=" + element);
axios.get(job_queue_url + "?guid=" + guid + "&file=" + element)
.then(function (res){
data_list.push(res.data);
console.log("Inside Loop: " + JSON.stringify(data_list));
})
.catch(function (error){
console.log(error);
});
}
console.log("Data List: " + JSON.stringify(data_list));
return JSON.stringify(data_list);
}
Solution 1:[1]
Javascript is single threaded and thereby loops are usually blocking, but in this case your promises will put it's new tasks at the end of the stack. If you use await no new task should be created and it should behave as you want. But you are making it sycronus so it will be a little slower than before.
async function retrieve_s3_file(to_do_list, guid){
var data_list = [];
for (let i = 0; i < to_do_list.length; i++)
{
element = to_do_list[i];
console.log("\n\nOutgoing request /jobs/list?guid=" + guid + "&file=" + element);
await axios.get(job_queue_url + "?guid=" + guid + "&file=" + element)
.then(function (res){
data_list.push(res.data);
console.log("Inside Loop: " + JSON.stringify(data_list));
})
.catch(function (error){
console.log(error);
});
}
console.log("Data List: " + JSON.stringify(data_list));
return JSON.stringify(data_list);
}
Solution 2:[2]
axios.get
is a promise. In javascript a promise is non blocking, meaning the callback given in the then
function will run once the promise resolve. But the promise won't block the thread.
The below example reflects the problem of the question. The console prints start
end
then ok
. Because customPromise
is a promise and it is called without the await
, the caller won't wait for that promise to finish, so the caller will continue the execution and print end
. Note that this promise is resolved immediately but the callback res => console.log(res)
will be executed at the end because its a promise callback.
const customPromise = new Promise((resolve, reject)=>{resolve('ok')})
function nonBLockingExample (){
console.log('start');
customPromise.then(res => console.log(res));
console.log('end');
}
nonBLockingExample();
Below is an example of the desired output. The caller waits for the customPromise
to resolve because customPromise
is called with the await
keyword.
const nonBlockingPromise = new Promise((resolve, reject)=>{resolve('ok')})
async function bLockingExample (){
console.log('start');
await nonBlockingPromise.then(res => console.log(res));
console.log('end');
}
bLockingExample();
So to apply the fix to your code, just await axios.get
. (await axios.get(.....
)
Solution 3:[3]
If you use asynchronous operation it won't block.
You can use await
keyword if you want Axios to wait before the request ends otherwise use promises.
Collect them and using Promise.all
you can get all the responses as an array when all requests are resolved.
async function retrieve_s3_file(to_do_list, guid) {
const requests = [];
for (const file of to_do_list) {
const params = new URLSearchParams({ guid, file });
const request = axios.get(`${job_queue_url}?${params.toString()}`);
requests.push(request.then((response) => response.data));
}
return Promise.all(requests).then(JSON.stringify);
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
Solution | Source |
---|---|
Solution 1 | Griffin |
Solution 2 | EEAH |
Solution 3 | n1md7 |