1

I have the following code:

let tasks;

try {
    await checkMongoConnection();
    const tasks = await Task
        .find()

    await disconnectMongo();

    if (!tasks) { return reject(); }
    // Is is possible to use the same naming?
    tasks = tasks;
} catch(error) {
    console.log(error.message);
}

In JS is it possible to use the same naming like this? e.g. tasks = tasks and set the variable outside the try block or do I have to use a new name e.g. tasks = fetchedTasks?

Kex
  • 8,023
  • 9
  • 56
  • 129
  • No, use a different name. – Patrick Roberts Sep 16 '20 at 15:31
  • 1
    Why are you defining a new variable in the first place ? – Titus Sep 16 '20 at 15:31
  • what's `return reject();`? – apple apple Sep 16 '20 at 15:34
  • As a side note, please try to avoid the [promise constructor antipattern](https://stackoverflow.com/q/23803743/1541563). – Patrick Roberts Sep 16 '20 at 15:38
  • 1
    If the `reject()` in the code above is from a promise executor (`new Promise((resolve, reject) => ...`), you might want to [read this](https://stackoverflow.com/questions/23803743/what-is-the-explicit-promise-construction-antipattern-and-how-do-i-avoid-it). You almost never need or want to use `new Promise` in an `async` function or when dealing with something that gives you a promise (like `Task.find()` apparently does). – T.J. Crowder Sep 16 '20 at 15:39
  • @PatrickRoberts fairly new to JS as you probably gathered. I set the variable like that to avoid try blocks within try blocks.. – Kex Sep 16 '20 at 15:40
  • Thanks for these comments. I'm rethinking my async approach. – Kex Sep 16 '20 at 15:50
  • it is because of [lexical scoping](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Closures) in short: JavaScript can look outside for variables and names, however can never look in for values/variables – Ctfrancia Sep 16 '20 at 15:50

1 Answers1

2

No, you can't access the tasks variable in the outer scope from the inner scope if you have a tasks variable in the inner scope. You can assign to an outer scope variable, but not when it's shadowed by an inner scope variable with the same name.

In the example, you don't need the outer tasks so I would just remove it (and the tasks = tasks statement). Or if you need it for some reason, remove the inner tasks declaration (just remove const from in front of it) so the code in the try block assigns to the outer tasks.

T.J. Crowder
  • 1,031,962
  • 187
  • 1,923
  • 1,875
  • It's an anti pattern setting an outside variable like that? The reason I do it is because I have multiple try blocks and it would be spaghetti hell if I put try blocks within try blocks... – Kex Sep 16 '20 at 15:38
  • @Kex - No, Patrick was referring to the `reject()` in the code and assuming it comes from `new Promise`, see the (new) comments on the question. That said, assigning to an outer scope variable from an inner scope is often less than ideal -- but other times it's fine, so... :-) – T.J. Crowder Sep 16 '20 at 15:40
  • @Kex sounds like you're already violating the [single responsibility principle](https://en.wikipedia.org/wiki/Single-responsibility_principle) then. Put each independent piece of logic in a separate async function and just await its call. Doing that should allow you to avoid writing nested `try` blocks. – Patrick Roberts Sep 16 '20 at 15:40
  • What if you have an async function that fails and catch is triggered with the error. In that error block I want to write the message to the database which requires another async call, so I'd have to do another try and catch for that in the catch block. That's my main issue. @PatrickRoberts – Kex Sep 16 '20 at 15:49
  • 1
    @Kex - It's just like with synchronous functions: Ideally, you don't have a `try`/`catch` at all except at the outermost (or at least *an* outer) layer that handles all of the errors from the nested calls within it. That way, other than a coordinating function, the functions just do what they do (or fail, and the error propagates). In an `async` function, promise rejections are exceptions (and exceptions are promise rejections). One of the big strengths of `async` functions over synchronous functions returning promises explicitly is that rejections propagate up the call tree. :-) – T.J. Crowder Sep 16 '20 at 15:54
  • 1
    If you *do* need to write to the database from within a `catch` block, that's fine, but make sure that code in the `catch` block doesn't throw (reject) and hide the original error (which is, again, just like a synchronous function). – T.J. Crowder Sep 16 '20 at 15:56
  • I get what you're saying. I could use a single error catch, identity the error in the catch block and then handle it appropriately. But at some point I need to make an async call to the database to log the error. Would calling a function in the error block `handleError(error)` that does the async database write be an antipattern? – Kex Sep 16 '20 at 15:58
  • 1
    @Kex - Not in *my* view, FWIW, provided any errors it raises don't shadow the error you're reporting. :-) Since an error reporting an error isn't usually one you want to propagate, you might have `handleError` ensure that it never rejects its promise / throws an error. Use `await` if it returns a promise and you want the `async` function you're calling it from to wait until it completes, or don't if you're fine with the error report running in parallel (ish) with whatever's next. – T.J. Crowder Sep 16 '20 at 16:35
  • 1
    Thanks a lot for the discussion. Really appreciate it. – Kex Sep 17 '20 at 02:49