This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I can't find way to fix this bug, I tried so many things but it's not working, IDK what am I doing wrong.
I have a function which should return array of objects with questions, but it returns array with length 0 so I can't iterate over it. I am using axios to make api call.
I am also bubble sorting the difficulty property inside the array object, so it starts from easy and goes to hard.
let getQuestions = () => {
let questions = [];
axios
.get('https://opentdb.com/api.php?amount=10')
.then((res) => {
for (let i = 1; i < res.data.results.length; i++) {
for (let j = 0; j < res.data.results.length - 1; j++) {
if (
res.data.results[j].difficulty.charCodeAt(3) <
res.data.results[j + 1].difficulty.charCodeAt(3)
) {
const temp = res.data.results[j];
res.data.results[j] = res.data.results[j + 1];
res.data.results[j + 1] = temp;
}
}
}
for (const i in res.data.results) questions.push(res.data.results[i]);
})
.catch((err) => console.error(err));
return questions;
};
console.log(getQuestions());
<script src="https://cdn.jsdelivr.net/npm/axios/dist/axios.min.js"></script>
If you are using the returned value then the issue is axios takes time to fetch the data from the API, but in the meantime control moves forward and executes the return statement at which point the value of questions is []. I would suggest using async await syntax instead of then() callback. You simply await for the response from the API and when the response is received the only you return the response from the function.
Related
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Async Function leaving array blank outside of scope [duplicate]
(4 answers)
Closed 9 months ago.
I have started learning javascript recently and started a new project.
So my problem here is that have this call to an API, everything is good I can access to the names of the pokemons. But when I try to get a return it keep telling me is undefined. I have already try diferents solutions but nothings works.
Console of edge
function arrayOptions(pk) {
fetch('https://pokeapi.co/api/v2/pokemon?limit=10')
.then((res) => res.json())
.then((data) => {
for (let i = 0; i < data.results.length; i++) {
console.log(i, data.results[i].name);
pk.push(data.results[i].name);
}
});
return pk;
}
var pk = [];
pk = arrayOptions(pk);
console.log(pk[0]);
This question already has answers here:
Using async/await with a forEach loop
(33 answers)
How do I return the response from an asynchronous call?
(41 answers)
Closed 2 years ago.
I am trying to create a filtered array in an array of objects. I am doing so by running case switch in a forEach and deriving a new array attaching that to a new object and pushing that object to an array stored outside of the foreach. but after running the foreach the length of the external array still shows 0 and the rest of the equation relates to the processing of said array. Its two very large blocks of code so i've tried to redact some.
let updatedDrop = []
drop.forEach(async(tollFree) => {
const zipCodes = Object.values(tollFree)[0].split(",");
let updatedList = []
const {
tracking,
mailList,
} = tollFree;
zips = await Zip.find({
"class": { "$in": zipCodes },
});
zips = zips.map(zip => zip.zip4)
switch (zipCodeSuppress) {
case "keepSelect":
(insert case switch)
break;
}
const distinct = (value, index, self) => {
return self.indexOf(value) === index;
};
updatedList = updatedList.flat()
updatedList = updatedList.filter(distinct)
const combinedCost = unitCost + postageCeiling
const dropItem = {
updatedList,
tracking,
}
updatedDrop.push(dropItem)
//console.log(dropItem)
})
console.log(updatedDrop.length)
let advJobs = [];
let cspJobs = [];
let wbJobs = [];
if (updatedDrop.length > 0){ .....
so until i am able to access the updated asynchronous data the rest of the formula is stalled. How do I do this?
The problem you are facing is that the forEach callback doesn't block the main thread, so at the moment you access the array right after the declaration of the forEach, the callback inside didn't finish executing.
Look at this example
const timer = 2000;
const numbers = [1, 2, 3];
const emptyArray = [];
async function getNumberTwo() {
return new Promise((resolve) => {
setTimeout(() => resolve(2), timer);
});
}
async function withForEach() {
numbers.forEach(async (n) => {
const two = await getNumberTwo();
emptyArray.push(n + two);
});
console.log(emptyArray); // the array is empty here.
setTimeout(() => console.log(emptyArray), numbers.length * timer); // if I log the array after all the time has gone, the array has the numbers.
}
withForEach()
but now if you use for of, or even a normal for I would say
// all the declarations from before..
async function withForOf() {
for (const number of numbers) {
const two = await getNumberTwo();
emptyArray.push(number + two);
}
console.log(emptyArray); // now the array has what you expect it to have
}
withForOf()
So, in conclusion, you can use a normal for or a for of to make it work as you need.
This question already has answers here:
Using async/await with a forEach loop
(33 answers)
Closed 2 years ago.
The below JavaScript is returning a strange version of an array. The below forEach logs nothing to console. I'm probably missing something quite fundamental here, but I know for a fact that the array is populated...unless it's not populated until later due to being async and Chrome just evaluates the console.log after the fact?
let damageRollStringArr = []
monster.damage_types.forEach(async (damageTypeName) => {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
})
damageRollStringArr.forEach(el => console.log(el))
// Was returning an empty array[] with objects inside?
return damageRollStringArr
Thanks
demageRollStringArr.forEach (2nd foreach) wont wait for monster.demage_types.forEach (1st foreach) to execute although there is async await in the first forEach
To achieve what you want to do, try this,
let damageRollStringArr = []
const promises = monster.damage_types.map(async (damageTypeName) => {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
})
await Promise.all(promises)
damageRollStringArr.forEach(el => console.log(el))
return damageRollStringArr
Or, you can use normal for() loop to replace 1st foreach
let damageRollStringArr = []
for(let i = 0; i < monster.demage_types.length; i++) {
const damageType = await checkResponseAndReturnValue(await DamageTypesService.findDamageType(damageTypeName.trim()))
if (damageType !== null) {
damageRollStringArr.push(damageType.damage)
}
}
damageRollStringArr.forEach(el => console.log(el))
return damageRollStringArr
1st solution will run the loop parallel,
2nd solution will run the loop sequential
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 3 years ago.
To start things off, I'm fairly new to coding and JS, so maybe I'm misunderstanding something very basic here.
I built a script to check a .JSON file for any fields named "ID: XXXX". Its purpose is to return every article's unique identifier from a blog. The unique identifier is "XXXX" in this case.
The script does what it's supposed to, but when I return the values to my global variable article_identifiers, they're returned as a pseudo array. I can't access single values by indexing them via article_identifiers[i].
However, when I set a timeout, article_identifiers is returned as a normal array and I can access the values inside the array by using console.log(article_identifiers[i]).
Here's the code, for context:
var article_identifiers = [];
var url = '/articles.json';
fetch(url)
.then((response) => response.json())
.then(data => {
var article_amount = Object.keys(data.articles).length;
for (var i = 0; i < article_amount; i++) {
article_identifiers.push(data.articles[i].id);
}
})
setTimeout(function(){
console.log(article_identifiers);
},500);
Why do I have to set a timeout? Am I misunderstanding something about the way JavaScript code is processed? Does my console.log() fire before my for loop is finished? If so, why?
First off, thanks for the super fast replies!
Here's the solution:
var article_identifiers = [];
var url = '/articles.json';
await fetch(url)
.then((resp) => resp.json())
.then(data => {
var article_amount = Object.keys(data.articles).length;
for (var i = 0; i < article_amount; i++) {
article_identifiers.push(data.articles[i].id);
}
})
console.log(article_identifiers);
fetch() is an asynchronous function, so I just had to put an await before that.
I'll mark this one as a lesson to always check if a prebuilt function is async or not.
Thanks!
This question already has answers here:
How do I return the response from an asynchronous call?
(41 answers)
Closed 4 years ago.
I have a route which performs 2 queries in 2 different databases like so:
app.post('/location',function(req,res){
Db.find({id:anId},function(err,doc){
myDocs=[]
for (var i = doc.length - 1; i >= 0; i--) {
myDocs.push(doc[i])
otherDocs=[]
otherDb.find({id:doc[i].id},function(err,doc2){
for (var i = doc2.length - 1; i >= 0; i--) {
otherDocs.push(doc2[i])
}
})
myDocs.push(otherDocs)
}
res.send(myDocs)
})
})
The issue here is that otherDocs is local to the anonymous function in otherDb, I am not able to access it from outside and push it into myDocs. How would I be able to do this?
You don't have a scoping problem, you have an asynchronous problem. Because the inside of your loop has asynchronous code, you'll have to wait for the callbacks to finish first before pushing them to myDocs and res.sending them.
Easiest solution to this would be to make the function async and then await each inner .find (transformed into a Promise):
app.post('/location',function(req,res){
Db.find({id:anId}, async function(err,doc){
const myDocs = [];
for (const oneDoc of doc.reverse()) {
myDocs.push(oneDoc);
const doc2 = await new Promise(res => {
otherDb.find({id: oneDoc.id}, (err,doc2) => res(doc2));
});
myDocs.push(doc2.reverse());
}
res.send(myDocs);
});
});
Note that this will iterate through each oneDoc's find one-by-one - if you want to send all requests at once rather than in parallel, use Promise.all instead.