Javascript why return empty array [duplicate] - javascript

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)
})()

Related

Why i can't pass variables with my function? [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 1 year ago.
I have this code in my react native app that is using firebase :
let bestTutors = [];
const getBestTutors = async () => {
const snapshot = await getDoc(docRef);
bestTutors = snapshot.data().list;
}
getBestTutors();
console.log(bestTutors);
But when i run it it only console logs "Array[ ]", I've tried to using .then( ) and all kind other stuff that doesn't make sense for me, idk if there's a wey to use it without the await or How can i pass the data to the variable :( ?
Look at my comments
Your Code 1
let bestTutors = [];
const getBestTutors = async () => {
const snapshot = await getDoc(docRef);
bestTutors = snapshot.data().list;
}
getBestTutors(); // Asynchronous function
console.log(bestTutors); // this is called before getBestTutors() returns the data. So console.log(bestTutors) return de default value: []
The new code
let bestTutors = [];
const getBestTutors = async () => {
const snapshot = await getDoc(docRef);
bestTutors = snapshot.data().list;
}
await getBestTutors(); // Wait until getBestTutors() has finished and then Next.
console.log(bestTutors);
call function with await. Like this one
await getBestTutors()

Promises making API calls in JavaScript with async/await syntax

Trying to get a better grasp on Promises with async/await syntax. .then().catch() feels more straightforward with the added visual cues and structure.
Do these two async/await functions make any logical sense for making multiple API calls and acting on the data once they're resolved?
The goal is to have a function that takes the url, number of additional pages and returns data from all calls in one output. It works but is slow enough to lead me to believe its pretty inefficient. (I'm sure the nested loops dont help)
async function getData(url, numOfPages) {
try {
const response = await axios.get(url)
const { results, next: nextUrl } = response.data
const nextPages = await getNextPages(nextUrl, numOfPages)
const finalData = results.concat(nextPages)
finalData.forEach(data => console.log(data.name))
}
catch (err) {
console.log(err)
}
}
getData('https://swapi.dev/api/planets/', 3)
async function getNextPages(nextUrl, numOfPages) {
try {
const response = await axios.get(nextUrl)
const data = response.data.results.map(res => res)
let nextPage = response.data.next
for (let i = 1; i < numOfPages; i++) {
let response = await axios.get(nextUrl)
let results = response.data.results
nextPage = response.data.next
for (let i = 0; i < results.length; i++) {
data.push(results[i])
}
}
return data
}
catch (err) {
console.log(err)
}
}

Async - await not executing callback in a for loop [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 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.

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.

Can an async function return undefined instead of a Promise [duplicate]

This question already has answers here:
Removing undefined values from Array
(14 answers)
Closed 3 years ago.
I am working on an app using nodejs. I am making multiple HTTP requests with an async function and axios library. However I do not always want to return the fetched data from my http request, only if a certain condition is met.
Like so.
const getFooHTTP = async (id) => {
let response = await axios.get(url);
if (condition){
//I only want to return the response here
return response;
}
//Here i do not want to return the response
}
Then I am getting all the promises returned in an array with Promise.all()
const getAllData = async() => {
let dataArray = [];
for (let i = 0; i < n; i++){
const data = getFooHTTP(i);
dataArray.push(data)
}
const someData = await Promise.all(dataArray);
return someData ;
}
Then I get all the data
getAllData().then(data => {
//Here is the problem, here I get a bunch of undefined in my data array
console.log(data);
})
Here is my problem, when I get the returned data from getAllData, there is some undefined element because at the first function in the beginning (getFooHTTP) was returning nothing. My question is how can I return promises conditionally, so I don't get undefined promises returned even If the async function have no return statement.
Thank you
An async function will always return a Promise, no matter what. If you explicitly return a non-Promise even if there are no awaits before it, it will be automatically wrapped in a Promise before returning (eg return undefined will turn into something like return Promise.resolve(undefined)).
const prom = (async () => {
return undefined;
})();
// Even though it returned undefined, it's still a Promise:
console.log(typeof prom.then);
If you don't want to return values that don't fulfill condition, filter the Promise.all before returning it:
const getFooHTTP = async (id) => {
let response = await axios.get(url);
if (condition){
//I only want to return the response here
return response;
}
//Here i do not want to return the response
return undefined;
// or, have no return statement at all
};
and
const getAllData = async() => {
let dataArray = [];
for (let i = 0; i < n; i++){
const data = getFooHTTP(i);
dataArray.push(data)
}
const someData = (await Promise.all(dataArray))
.filter(val => val !== undefined);
return someData ;
};
Though, this relies on all of the Promises that getFooHTTP resolves to returning non-undefined values.

Categories

Resources