1

This is my code:

let curId;
if (!user) {
  db.collection("users")
    .add({
      name: name,
    })
    .then((doc) => curId = doc.id)
    .catch((err) => console.error(err));
} else {
  curId = user.id;
}
console.log(curId); <-- I need curId here

Currently I get undefined for curId because I am not waiting for the async code to finish running. What is the best way to achieve this?

Some approaches I've thought of:

  • Use await instead of .then but I feel like this may look less organized/messy with the try and catch
  • I could also add what I want to do with curId in both the if and the else statement but I'd rather not write redundant code
Ken
  • 1,155
  • 2
  • 19
  • 36
  • 2
    That's what `async` and `await` were designed to do. The database function is asynchronous, and JavaScript doesn't wait. The `async` function and `await` expression are meant to simplify and clarify the implementation of handling asynchronous results. – Pointy May 23 '21 at 17:24
  • Thanks, is there a neater way of handling errors with `async` and `await` other than with a `try` `catch` block? I really prefer the simplicity of the `.catch` – Ken May 23 '21 at 17:25
  • 2
    Catching errors just to log them is usually a bad idea. If you can't handle, let errors bubble up. – Jonas Wilms May 23 '21 at 18:02

1 Answers1

1

With asynchronous code you should perform actions that require waiting for a result in a .then(). With this I see a few options:

  1. Put this into a function that returns a promised value
  2. Call a function to do your logic with curId
  3. Restructure to a single promise

Option 1

const getCurId = (user) => {
  if (!user) {
    return db.collection("users")
      .add({ name: name })
      .then((doc) => doc.id)
  } else {
    return Promise.resolve(user.id);
  }
};

getCurId().then(curId => {
  console.log(curId); // do things with curId here
}).catch((err) => console.error(err));

Option 2

if (!user) {
  db.collection("users")
    .add({ name: name })
    .then((doc) => doc.id)
    .then(doThingWithCurId)
    .catch((err) => console.error(err));
} else {
  doThingWithCurId(user.id);
}

const doThingWithCurId = (curId) => {
  console.log(curId); // do things with curId here
};

Option 3

const curIdPromise = user ? Promise.resolve(user.id) : db.collection("users")
  .add({ name: name })
  .then((doc) => doc.id);

curIdPromise.then((curId) => {
  console.log(curId); // do things with curId here
}).catch((err) => console.error(err));
domdomegg
  • 1,498
  • 11
  • 20
  • The new(ish) `async` function and `await` expression were designed to clean up this coding pattern. – Pointy May 23 '21 at 18:06
  • …and notice that `curId` actually will be `undefined` when there was an error in the db operation. The error handling always should go in the end, unless one a) rethrows the error or b) returns a fallback value – Bergi May 23 '21 at 19:10
  • Good point @Bergi, and many thanks for your edits. I've also moved the catches to the end – domdomegg May 23 '21 at 20:08