Markus
Markus

Reputation: 17

Trouble understanding async/await nodejs

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

Answers (2)

Prince Hernandez
Prince Hernandez

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

Bergi
Bergi

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 _ids 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

Related Questions