Problem: Code not pausing before returning an async function to assign the result in a variable

Hi everyone!

I’m having an issue that I don’t understand with my Express + MongoDB + bcrypt code.

I know how to solve it, but I’d like to understand why it’s happening.

const storeNewUserIntoDatabase = async (user) => {
  const newUser = { ...user, access: true, admin: false };
  await bcrypt.hash(user.pass, saltRounds, async (error, hashedPass) => {
    if (error) throw new Error(error);
    const result = await Users.insert({ ...newUser, pass: hashedPass });
    if (!result) return '';
    return result;
  });
}

// Route -------------------------------------------------

auth.post('/signup', async (req, res) => {
  try {
    let response;
    const {
      name, email, pass, confirmPass,
    } = req.body;
    if (pass !== confirmPass) {
      response = {
        ok: false,
        message: 'The passwords do not match',
      };
    }
    
    // This line below is the one that's causing problems...
    const successfullNewUserId = await storeNewUserIntoDatabase({ name, email, pass });

    if (!successfullNewUserId) {
      response = {
        ok: false,
        message: 'Operation failed, no user was added to the database',
      };
    } else {
      response = {
        ok: true,
        message: 'User created successfully',
        user_id: successfullNewUserId,
      };
    }
    res.send(response);
  } catch (err) {
    throw new Error(err);
  }
});

I thought that the ‘await’ keyword would pause the execution of the code until ‘storeNewUserIntoDatabase’ returned it’s value, but the ‘if’ statements below execute with ‘successfullNewUserId’ being ‘undefined’, even when the user was actually successfully added to the database.

I can modify the function ‘storeNewUserIntoDatabase’ to execute a callback, and that would fix it, but I’d like to understand WHY the await is not working in this case like it usually does.

Thank you so much for reading!

John

Hello there,

It does not appear the function returns anything:

const storeNewUserIntoDatabase = async (user) => {
  const newUser = { ...user, access: true, admin: false };
  await bcrypt.hash(user.pass, saltRounds, async (error, hashedPass) => {
    if (error) throw new Error(error);
    const result = await Users.insert({ ...newUser, pass: hashedPass });
    if (!result) return '';
    return result;
  });
}

So, successfullNewUserId will always be undefined

Hope this helps

1 Like

Hi @Sky020,

Thank you for answering!

Good observation. I changed my code to return something from that function, but it didn’t make any difference for the problem I was having.

Here is what the code looks like now:

const signInUser = async (user) => {
  const newUser = { ...user, access: true, admin: false };
  const resultFromHashing = await bcrypt.hash(user.pass, saltRounds, async (error, hashedPass) => {
    if (error) throw new Error(error);
    const result = await Users.insert({ ...newUser, pass: hashedPass });

    console.log(`Result INSIDE the bycrpt callback: ${result} // This happened in second: ${new Date().getUTCSeconds()}`);

    return result;
  });

  console.log(`Result OUTSIDE the bycrpt callback: ${resultFromHashing} // This happened in second: ${new Date().getUTCSeconds()}`);

  if (!resultFromHashing) return '';
  return resultFromHashing;
};

And this is what the console looks like with the logs (notice how the result from outside the callback is still being called first, even though I’m awaiting the callback):

Result OUTSIDE the bycrpt callback: undefined // This happened in second: 5
Result INSIDE the bycrpt callback: 5fc7f11ac363a4b06f7a15b0 // This happened in second: 6

It’s quite a mystery to me. I think that if I’m able to understand this, it will deepen my understanding of how async/await and promises in general work, so I’m excited!

Then, my understanding is that the hash method does not return a promise, unless the callback (async (error, hashedPass) =>) is not given.

So, you might find more information by console.loging the resultFromHashing. Essentially, what you might be looking for is:

const resultFromHashing = await bcrypt.hash(user.pass, saltRounds);
resultFromHashing.then(DBStuff)...

Hope that helps

1 Like

I managed to solve the problem. It was a mistake in the way I was using bcrypt asynchronously. Here is the corrected code:

const signInUser = async (user) => {
  const newUser = { ...user, access: true, admin: false };
  const hashedPassword = await bcrypt.hash(user.pass, saltRounds);
  if (!hashedPassword) return null;
  const result = await Users.insert({ ...newUser, pass: hashedPassword });
  return result;
};

A lot simpler than I thought :slight_smile:.

Thanks @Sky020!

Have a great day!

John

1 Like