1

I am confused with certain parts regarding promises, I have read multiple articles and I have seen multiple videos and I want to ask a few things:

from what I understand currently, when a promise is created is starts running.

Do I need to await on the promise if the value that returned from the promise is not used in the code ?

a scenario for that is: let's say I am processing a task in my system and I want to log the information to mongodb, when I invoke the insert function I get a promise back. the execution beings but I don't care about the result of it

if I am not awaiting and there is an error I wouldn't be able to handle it.

A followup question to the question above:

from what I read whenever I await it actually blocks the execution of the async function, but if it blocks the execution of the function how doesn't it block the rest of the eventloop ?

Eitank
  • 570
  • 8
  • 21
  • 2
    "*from what I understand currently, when a promise is created is starts running.*" not quite. A promise is not "running". A promise is a *notification mechanism* only. Once *something* is running, you get a promise for its result. – VLAZ Sep 29 '21 at 11:07
  • 2
    "*from what I read whenever I await it actually blocks the execution of the async function,*" `await` doesn't *block*. It suspends the function and only restores it when the promise that is `await`-ed is resolved. – VLAZ Sep 29 '21 at 11:08
  • _"await it actually blocks the execution of the async function, but if it blocks the execution of the function how doesn't it block the rest of the eventloop ?"_ - while the async function is _paused_, javascript can do other things and once the promise is settled, it's reaction callbacks are put in a micro-task queue and from there they are pushed on to the call stack. – Yousaf Sep 29 '21 at 11:08
  • Somewhat relevant: [Please point out the misfacts in my learning regarding Asynchronous Javascript](https://stackoverflow.com/q/65833787) – VLAZ Sep 29 '21 at 11:09
  • Also relevant: [What are asynchronous functions in JavaScript? What is "async" and "await" in JavaScript?](https://stackoverflow.com/q/62196932) | [When does async function actually return a pending promise?](https://stackoverflow.com/q/67769474) – VLAZ Sep 29 '21 at 11:38

2 Answers2

6

Basic concepts

The whole point of the event loop is to have many microtasks that do not affect each other (hence by default there is no effect).

To chain microtasks first; there were callbacks, then Promises (then/catch) then the async/await API. The last two can be considered just syntactic sugar atop the callback concept. There are no 'functionalities' added but rather a different syntax to achieve the same stuff in simpler and more elegant ways (Pyhilosophicaly).

The event loop executes all the queued microtasks at each loop and repeats. Unless you have blocking code (and await is not to be considered blocking) your event loop never stalls and hence other tasks are not affected.

You are trying to understand await from the perspective of real blocking code as intended in other languages.

IMHO you first need to deeply understand how callbacks work, then study Promises (as a tool to make callbacks less messy) and then async/await (as a syntax to make Promises pretties). But keep in mind, the underlying system is the same: functions that call functions that get handled functions to be eventually called in future).

Specific questions

When a promise is created is starts running

Yes, but no. A promise does not run, a promise is only a contract you receive by a part of code that will be used to notify you of the outcome. So the promise does not run, is the mean that has been created for you after you requested a task to be executed.

So typically if a promise has been handled to you there is something 'running'. But Promise may be used differently and there may be something 'waiting'.

A promise is not linked to the execution of the task hence it can not start nor stop it.

Do I need to await on the promise if I'm not interested in the outcome

No, you are not required to. But keep in mind that not handling promise exceptions is being deprecated and may result in system failure. You should always handle (or let bubble) exceptions.

There would be a failure if there is an unhandled promise rejection. In synchronous code this is equivalent to an uncaught thrown error. Until now(-ish) uncaught promise rejections were tolerated but there isn't a really good reason for that. Node is moving to treat them the same as any other error that bubbles to the top.

VLAZ

You are considering promises only with async/await but the underlying Promise api is .then() and .catch(). Using this API you can use promises in a 'fire-and-forget' fashion:

async function Do() {
  await before();
  asyncDbCall().catch(err => console.error(err))
  await after();
}

In this example you are not waiting for asyncDbCall() but still .catch(err => console.error(err)) will result in the error being logged (some time in the future, probably even after Do() has completed).

Or you can branch off the execution to other async executions, take this complex example:

async function Do() {
    await before();
    // This will execute AFTER before() & only if before() succeeded
    asyncDbCall()
        .then(async value => {
            // This will execute after `asyncDbCall()` and only if it succeeded
            await something(value);
            // We reach here after `something()` and only if succeeded
        })
        .catch(err => {
            // This will execute if `asyncDbCall()` fails of IF ANYTHING
            // within `async value => {}` fails
            console.error(err);
        })
    // This will execute AFTER before() and only if before() succeeded and
    // asyncDbCall() call (but not Promise) succeeded
    await after();
}

Await it actually blocks the execution of the async function

Await stops the async function (hence also anything that is awaiting for the function) but does not affect anyway the event loop.

Newbie
  • 4,462
  • 11
  • 23
  • So if an async function awaits on a promise it will not block the eventloop from continuing to process the next call to the function? – Eitank Sep 29 '21 at 11:32
  • "*keep in mind that not handling promise exceptions is being deprecated and may result in system failure.*" I do support this point. Just a small clarification, there would be a failure if there is an unhandled promise rejection. In synchronous code this is equivalent to an uncaught thrown error. Until now(-ish) uncaught promise rejections were tolerated but there isn't a really good reason for that. Node is moving to treat them the same as any other error that bubbles to the top. – VLAZ Sep 29 '21 at 11:33
  • Is there a scenario where i should not await ? – Eitank Sep 29 '21 at 11:35
  • @Eitank Whenever you want to do a fire-and-forget or branch-off the execution (eg not wait for completion but go on). See the example I just added. – Newbie Sep 29 '21 at 11:42
  • 1
    @VLAZ You made a good point. I plagiarized it and added it to the answer ;) – Newbie Sep 29 '21 at 11:43
  • branch off the execution followup question: @VLAZ does it add the tasks in the branched out execution to the micro queue task ? and if it does it does it affect other promises like the one in the promise we await on form the `after` method ? – Eitank Sep 29 '21 at 15:08
  • 1
    @Eitank there is no branching execution *by default*. Multithreading is an opt-in in JS and async tasks are normally still handled in single thread. See my answer to [Please point out the misfacts in my learning regarding Asynchronous Javascript](https://stackoverflow.com/q/65833787) for more explanation. Any promise completion is added to the microtask queue before it is processed. If you have some fire and forget task then all that happens is that the function it's in will not wait for it to complete and would just continue normally. Having that task resolve would thus still add an – VLAZ Sep 29 '21 at 15:17
  • @Eitank entry in the microtasks queue but it wouldn't "affect" other microtasks. They are still isolated. Unless the tasks are chained (via `await` or `then`, etc) whether `a` resolves before `b` or vice versa will not matter. They each will finish *at some point* anyway. If you do need them to finish in a specific order, then you need to chain them. You should ***never*** rely on the order of resolution of independent promise chains. – VLAZ Sep 29 '21 at 15:17
  • what happens if the branched out tasks take 10 seconds and the task from `after` is another 2 seconds but queued afterwards, will the task before affect it ? I just have to know because we experience weird things in terms this pattern @VLAZ – Eitank Sep 29 '21 at 15:22
  • @Eitank if you have `doAsync10s(); await doAsync2s()` then the whole operation should take *about* 10 seconds. The 10s task is not awaited, so it finishes when it finishes (10s from now). The 2s task is awaited but finishes before the 10s one, so it doesn't matter. If we flip them around and do `doAsync2s(); await doAsync10s()` it's still the same. The 2s task will finish while the 10s task is being awaited but it also doesn't matter since they are supposed to be separate. – VLAZ Sep 29 '21 at 15:27
  • what happens if `doAsync10s()` is awaiting within it for a big task and then we have `await doAsync2s()` like you described ? or did you just describe this scenario ? also what happens in terms of the micro task queue ? how does it make sense that the task enqueued inside of `doAsync10s()` doesn't affect the one generated by `await doAsync2s()` ? @VLAZ – Eitank Sep 29 '21 at 15:30
  • @Eitank async tasks shouldn't take (significant) processing time. If you have something like a busy wait in your async function then it still holds up the entire thread and everything else with it. But lightweight tasks that don't hog the CPU have no issues. `await a(); b()` acts the same as `a().then(b)` - it will start the task from `a`, you get a promise for it, once resolved, it will be added to the microtask queue. The next time the event loop picks it up, it will call `b`. Whether or not there were other tasks before `a` completes doesn't matter. https://jsbin.com/febujux/edit?js,console – VLAZ Sep 29 '21 at 15:39
0

from what I understand currently, when a promise is created is starts running.

It is not. It has its internal state set to pending. Promise's constructor takes a callback as an argument, and in turn provides it with resolve and reject callbacks.

What it also does is that it allows to provide a number of actions that happen when it's state changes to resolved or rejected. Outside of async/await, you might know them as .then and .catch instance methods of Promise class. Once the state is changed, they will be executed.

Do I need to await on the promise if the value that returned from the promise is not used in the code?

No, that is entirely up to you.

a scenario for that is: let's say I am processing a task in my system and I want to log the information to mongodb, when I invoke the insert function I get a promise back. the execution beings but I don't care about the result of it

if I am not awaiting and there is an error I wouldn't be able to handle it.

You can still use .catch to handle the error without awaiting for the Promise to finish

A followup question to the question above:

from what I read whenever I await it actually blocks the execution of the async function, but if it blocks the execution of the function how doesn't it block the rest of the eventloop?

Promises have nothing to do with the event loop.

You can read more about the EventLoop here.

baldrs
  • 2,132
  • 25
  • 34