Reputation: 17
Ok so I´m having troubles understanding how async/await, Promises, etc. in nodejs work, this is my first time programming in an asynchronous language.
What im trying to do here is basically select one random entry from the mongoose-model "SecSolution". Currently when arr is returned it´s empty, and the debug message on the bottom gets printed before the debug on the top gets printed. I just want the function to return "arr" after it gets its value.
async function getRandomCardIds(deckIdentifier, cardCount) {
let arr;
switch (deckIdentifier) {
case 102:
await SecSolution.count().exec(async function (err, count) {
let promises = [];
var random = Math.floor(Math.random() * count);
for (let i = 0; i < 2; i++) {
promises.push((await SecSolution.findOne().skip(random).lean())._id);
}
arr = await Promise.all(promises);
debug("This gets printed second" + arr);
});
break;
}
debug("this gets printed first");
return arr;
}
Thanks in advance!
Upvotes: 0
Views: 1462
Reputation: 3721
well basically you have to think that it will try to run everything and all the code that needs to wait to be resolved wont stop the process of running all the code.
thus, looking at your code, we can see the following:
1) define arr
as undefined
then go inside the switch.
2) in the switch statement we have an await
so it will wait (but it wont stop the other code to run because it is not on the same statement), it will resolve later.
3)prints the debug
message
4) returns undefined
because the await inside of switch is not resolved.
5) one day the statement is resolved but nothing you can do about it.
an example could be the following.
function resolveAfter2Seconds() {
return new Promise(resolve => {
setTimeout(() => {
resolve('resolved');
}, 2000);
});
}
async function asyncCall() {
console.log('calling');
var result = await resolveAfter2Seconds();
console.log(result);
// expected output: "resolved"
}
asyncCall();
so what you can do in your case is the following:
function resolveInnerFunct() {
return new Promise(resolve => {
let promises = [];
var random = Math.floor(Math.random() * count);
for (let i = 0; i < 2; i++) {
promises.push(SecSolution.findOne().skip(random).lean())._id));
}
Promise.all(promises).then(values=> {return resolve(values)};
});
}
async function asyncCall() {
console.log('calling');
let arr;
switch (deckIdentifier) {
case 102:
// this will wait until the resolveInnerFunct resolves.
arr = await resolveInnerFunct();
debug("this wont get printed before the other message")
break;
}
debug("this gets printed first");
return arr;
}
asyncCall();
Upvotes: 0
Reputation: 664548
Do not use callbacks when working with async
/await
. (And when working with plain promises, use only then
callbacks). Also you shouldn't use await
on a promise that you still need as a promise object, to pass it to Promise.all
. Your code should be
async function getRandomCardIds(deckIdentifier, cardCount) {
switch (deckIdentifier) {
case 102:
const count = await SecSolution.count(); // a promise(like object)
let promises = [];
var random = Math.floor(Math.random() * count);
for (let i = 0; i < 2; i++) {
promises.push(SecSolution.findOne().skip(random).lean());
}
let arr = await Promise.all(promises);
debug("This gets printed second" + arr);
return [arr[0]._id, arr[1]._id];
break;
}
debug("this gets printed first");
return undefined;
}
Instead of accessing the _id
s on the objects in the result array, you could also have transformed the promises directly (similar to what you tried with the await
):
promises.push(SecSolution.findOne().skip(random).lean().then(card => card._id));
Upvotes: 1