Async - await not executing callback in a for loop [duplicate] - javascript

This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 2 years ago.
I have used the async function and waiting for one API to hit and display its current file name which got uploaded then increase the counter I and go for the next file.
ISSUE: The async and await is working fine but the callbacks are called after all the requests have been made.
How can I hit the API and get its name printed then go for another file to hit the API?
PS: I can't change callback to promise, it's a defined structure in my organization as of now.
Code:
uploadCallback = () => {
console.log(currentFile)
}
const loop = async() => {
for (let i = 0; i < this.state.fln.length; i++) {
currentFile = obj.fln;
await uploadAPI(obj, this.uploadCallback);
console.log('currentFile:', i, currentFile);
}
};

You could try something like this:
uploadCallback = () => {
console.log(currentFile)
}
const loop = async() => {
for (let i = 0; i < this.state.fln.length; i++) {
currentFile = obj.fln;
const res = await uploadAPI(obj);
this.uploadCallback(res);
console.log('currentFile:', i, currentFile);
}
};
This will make sure that the callback is called only after uploadAPI finishes.

You'll need to integrate promises. Here's an example with the Pokemon API...
let thisstateflnlength = 5
const getAPI = (counter = 0) => {
if (counter <= thisstateflnlength) {
fetch("https://pokeapi.co/api/v2/pokemon/ditto").then(response => response.json()).then(data =>{
console.log(data.forms[0])
console.log(counter)
}).then(data => getAPI(counter+1))
}
}
getAPI()
The counter logs from 0-5 and each API call is executed asynchronously.

Related

Promise.all in loop, one by one. Await until function fully completed [duplicate]

This question already has answers here:
Resolve promises one after another (i.e. in sequence)?
(36 answers)
Closed 1 year ago.
I'm trying to resolve promises one by one, but i don't understand how to. I want to wait till video message load fully then move to another promise, otherwise it freeze browser. In my code example it don't wait until video hit loadedmetadata event, and go to next promise. And after all promises executed, load's all videos. How it looks: https://prnt.sc/10mg4oc
//All messages loop
for (var i = 0; i < data[0].length; i++) {
let urls = [];
$.each(file_id.split(','), function( index, value ) {
file_id = value;
urls.push("//localhost/storage/"+data[0][i].user_id+"/"+data[0][i].file_cluster_id+"/"+value)
});
//Get chunks array from file cluster
let chunkPromises = urls.map(function callback(url,index) {
return fetch(url).then((res) => {
return res.arrayBuffer();
});
});
console.log(chunkPromises);
console.log(0);
//I'm trying to understand how to do it
(async function loop() {
await Promise.all(chunkPromises).then(chunks => {
console.log(chunks);
console.log(1);
//Appending file chunks to file back
for (const value of chunks) {
console.log(2);
}
video.attr('src', URL.createObjectURL(full_video));
console.log(3);
//I want that promise complete loadedmetadata, then go to another promise iteration
video.on("loadedmetadata", function () {
console.log(`${secondsReady} seconds of video are ready to play.`);
});
});
});
}
If it possible i woold like, not touch all messages loop.
You can actually use async/await in for loops, it doesn't work well with other forloop iteration like forEach, filter etc. :
const PromiseMe = () => {
return new Promise((res, rej) => {
setTimeout(() => {
res('Integrate Me');
}, 1000)
});
}
const main = async () => {
for(let i = 0; i< 10; i++) {
let val = await PromiseMe();
console.log(val);
}
}
main();
So, you can actually implement this in you for-loop like this.
const result = [];
const mockFunction = async () => {
for (var i = 0; i < data[0].length; i++) {
//Get chunks array from file cluster
//urls is an array
let chunkPromises = await fetch(url[i]);
result.push(chunkPromises); //parse this data to specific format if needed
}
console.log(result);

Javascript await inside a loop

I am trying to work with an api where I have to send a request for each item in a list.
However, I see that the loop doesn't seem to wait for every request, i.e, the loop doesn't work as expected. Here's the code below
getInfo = async () => {
const mylist = ["item1","item2","item3","item4","item5","item6","item7"]
const responses = []
const len = mylist.length
for (let i = 0; i < len; i++) {
//console.log("inside loop")
await axios.get("some_url/"+mylist[i])
.then(res => {
responses.push(res.data)
})
}
When I run the program, all the console.log("inside loop") executes immediately without waiting for the request to be complete.
How can I modify the code so as to wait for each response to be completed before updating the for loop counter variable?
You could try re-arranging the code to something like this. But using a Promise.all with Array.prototype.map would be more idiomatic solution for the problem.
await the async call (remove unnecessary .then call) and then console.log
getInfo = async () => {
const mylist = ["item1","item2","item3","item4","item5","item6","item7"]
const responses = []
const len = mylist.length
for (let i = 0; i < len; i++) {
responses.push((await axios.get("some_url/"+mylist[i])).data)
console.log("inside loop")
}
}
Internally, await is translated into a Promise chain. Since the for loop can't be transformed into a Promise-continuation, you'll need to convert it to a Promise-based construct.
Depending on what you want to achieve there are multiple ways to go about it.
Constructing the responses array could be done with a map statement.
const promises = mylist.map(item => {
return axios.get("some_url/"+item).then(res => { return res.data; })
});
const data = await Promise.all(promises);
No manual pushing items around or fiddling with the array length.

How to return values from an axios promise javascript [duplicate]

This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am trying to return a few lists with the axios api call i make from the javascript, however, i do not understand how to console.log() the result and pass it for my future use (trying to use it for a data visualization)
heres what i have
const axios = require('axios');
var years = []
var totals = []
var rail = []
var bus = []
var para = []
const getTotal = async () => {
const url="https://data.cityofchicago.org/resource/w8km-9pzd.json";
var totals = []
try {
let res = await axios.get(url);
for (i = 0; i < res.data.length; i++) {
totals.push(res.data[i].total);
years.push(res.data[i].year);
rail.push(res.data[i].rail);
bus.push(res.data[i].bus);
para.push(res.data[i].para);
}
}catch(error) {
console.log(error);
}
return(totals,years,rail,bus,para)
}
//data = axiosDataFetch().bus;
console.log(getTotal())
^^^ how do i print totals here instead of having it show as undefined?
i edited the code based on some answers i received, essentially i want to be able to call and use the 5 lists i got from the API into a data visualization.
Add an await keyword before the axios call, then instead of using the .then callback, do stuff with the res object.
const axios = require('axios');
async function axiosDataFetch() {
const url="https://data.cityofchicago.org/resource/w8km-9pzd.json";
var totals = []
let res = await axios.get(url);
for (i = 0; i < res.data.length; i++) {
totals += res.data[i].total;
}
console.log(res.result)
}
axiosDataFetch();
Javascript is designed with asynchronous behavior at its core (eg. it's unknown when the http call made by axios will return, so it's not guaranteed to be in sync with your program).
You can read more about the many, many ways to handle asynchronous behavior here. Long article, but will save you countless hours in the future if you can understand its content.
Try logging from inside your then. Your other log is being called before axios returns back a result.
const axios = require('axios');
const url="https://data.cityofchicago.org/resource/w8km-9pzd.json";
var totals = []
let res = axios.get(url)
.then(result=>function(response){
for (i = 0; i < response.data.length; i++) {
totals += response.data[i].total;
}
console.log(totals); // add this
}
)
.catch(function (error) {
console.log(error)
});
const axios = require('axios');
const url="https://data.cityofchicago.org/resource/w8km-9pzd.json";
const getTotal = async () => {
var totals = []
try {
let response = await axios.get(url);
for (i = 0; i < response.data.length; i++) {
totals.push(response.data[i].total);
}
console.log(totals);
} catch(error) {
console.log(error);
}
return totals;
}
sorry my fault, I didn't know that you wanted to execute the query at the top level, you have the pending response because the function getTotals is returning a function that is a promise. You can solve it doing the following
getTotal().then(result => {
console.log(result);
});
Usually we don't have this behaviour because we have our code modularised and when we import our file, our code is internally inside a IIFE.

Javascript why return empty array [duplicate]

This question already has answers here:
Why is my variable unaltered after I modify it inside of a function? - Asynchronous code reference
(7 answers)
Closed 2 years ago.
I know Js is async but how to prevent my callback from returning an empty array ?
Here is my code :
function getPicturesArray(nbr,callback){
var avatarArr = [];
for(var i =0; i<nbr ; ++i){
request("https://randomuser.me/api/",{json: true},(err,response,body)=> {
avatarArr.push(body.results[0].picture.large);
});
}
callback(avatarArr);
}
getPicturesArray(12, (e)=>{
console.log(e);
});
console.log('here');
And the sout is:
[]
here
I'm mocking the calls with a public service for demonstration purposes, but the key point here is the asynchronous nature of HTTP requests.
When you invoke callback(avatarArr);, your for loop IS done but the (in this case 12) requests you sent are not, so avatarArr does not have any items yet.
Notice async before function getPicturesArray, and await before fetch
await tells the execution to wait for the fetch call to finish
You MUST check out async/await.
async function getPicturesArray(nbr,callback){
var avatarArr = [];
console.log('loading...');
for(var i =0; i<nbr ; ++i){
const response = await fetch(`https://jsonplaceholder.typicode.com/todos/${i+1}`);
const json = await response.json();
avatarArr.push(json.title);
}
console.log('done loading...');
callback(avatarArr);
}
getPicturesArray(12, (e)=>{
console.log(e);
});
console.log('see how this is executed before done loading...');
Don`t use callbacks. Use Promises or async/await.
getUserPic = async () => {
const url = 'https://randomuser.me/api/'
const response = await fetch(url)
const users = await response.json()
return users.results[0].picture.large
}
;(async () => {
const userAvatars = []
for (let i = 0; i < 12; i++) {
userAvatars.push(await getUserPic())
}
console.log(userAvatars)
})()
Also try to use this.
In this case I advice you to use Set instead of Array to exclude duplicate items.
getUserPic = async () => {
const url = 'https://randomuser.me/api/'
const response = await fetch(url)
const users = await response.json()
return users.results[0].picture.large
}
getMultipleUserPics = async limit => {
const userAvatars = new Set()
while (userAvatars.size != limit) {
userAvatars.add(await getUserPic())
}
return userAvatars
}
;(async () => {
const userPics = await getMultipleUserPics(5)
console.log(userPics)
})()

Async/Await - code executes before promise is resolved [duplicate]

This question already has answers here:
How do I convert an existing callback API to promises?
(24 answers)
Closed 2 years ago.
I have an async function that processes an Array and call another async function by increasing time interval by each element.
I wait for all promises to resolve and then I save the resulting Array in a file. Though for some reasons the write file operation executes before the Promises are resolved.
Can somebody tell me what I might be doing wrong?
The read and write file functions are turned into promise with node util and the getGuidesList returns a promise.
(async () => {
try {
const file = await readFilePromise('./kommuner.json');
const municipalities = JSON.parse(file).municipalities;
console.log(municipalities);
const municipalities_new = await Promise.all(municipalities.map(async (municipality, index) => {
setTimeout(async () => {
let guides = await getGuidesList(municipality.municipality_id);
// const guides = [];
if (typeof guides === 'string') {
guides = [];
}
console.log(`Number of guides for ${municipality.municipality_name}: ${guides.length}`);
Reflect.set(municipality, 'guides_number', guides.length);
Reflect.set(municipality, 'guides', guides);
console.log(municipality)
}, index * 5000);
}))
console.log(municipalities_new);
await writeFilePromise('./kommuner_guide.json', JSON.stringify({
"municipalities": municipalities_new
}));
} catch (err) {
console.log(err);
}
})();
The problem here is this line:
setTimeout(async () => {
you do a setTimeout call. That will schedule the callback to be called later. But you don't wait for that callback to happen. Instead use some promisified version of setTimeout:
const timer = ms => new Promise(res => setTimeout(res, ms));
then you can
await timer(2000);
await /*other stuff*/;

Categories

Resources