Is resolving promise necessary after sending response to the client? - javascript

I need to call an asynchronous function after sending the response to the client.
res.json({});
someAsyncFunction(); //no await for this function
Would that be a bad thing to run that function without awaiting it's promise? Is it changing anything?

By itself, no. Awaiting makes sense if and only if you might want to do something at the time when the promise is fulfilled. If there is no imaginable case when you would have any use of doing anything at the point the promise is fulfilled, then it is sub-optimal to await and therefore slowing down the process. Yet, if you are able to have a .then() which is a non-blocker, by contrast to await, so only use await if your code cannot continue reasonably without the fulfillment.
So, there are three cases:
case 1: there is nothing to be waiting for. Then don't await.
case 2: there is something you might want to do when the promise is fulfilled, but you can let the code perform normally before that. Then don't await, use .then() instead
case 3: your code needs the fulfillment ASAP: Then await

Related

Why is a XHR Request treated as a macro-task while a Fetch request is treated as a micro-task?

So based on 2 StackOverflow answers, what I have understood is:
XHR callback is queued with Macrotasks
Fetch method is queued with Microtasks
So my question is:
Is this true?
If yes, why is it this way? Shouldn't both of them be treated in the same way?
Is this true?
No. Re-read the answer your linked:
When the the request response will be received […], the browser will queue a new task which will only be responsible of resolving that Promise, […]
I've emphasised the macrotask for you.
Shouldn't both of them be treated in the same way?
No, why would they? One is a promise API, the other is not. Notice that if you wrap XMLHttpRequest in a promise, you get exactly the same behaviour: the load/readystatechange event (a macro task) resolves a promise, scheduling any promise handler (a micro task).
But ultimately you should ask yourself: does it even matter? You normally shouldn't need to concern yourself with such timing details.
Is this true?
Yes.
When XMLHttpRequest was created there was no microtask queue. Only one - what is now called the macrotask queue.
However, when fetch() was introduced, promises were already in the standard. The result of fetch() is a promise and all effects after a promise resolution are done via the microtask queue:
setTimeout(() => console.log("macrotask done"), 0); //logged second
Promise.resolve().then(() => console.log("microtask done")); //logged first
Hence resolving the promise from fetch() will also add the subsequent handlers to the microtask queue. Again, it is the one used for the handlers all promises.
If yes, why is it this way? Shouldn't both of them be treated in the same way?
There is no requirement for the two to work the same. Nor would the resolution of these make much of a practical difference in day-to-day code.
Do note that the two are not really the same, either - fetch will resolve as soon as a result is returned before the body of the result is read. Hence why calling .json() or .text() is needed, see Why does .json() return a promise? - calling those methods that will actually process the body. XHR does not have this intermediate step required, its body is processed once it assumes ready state 4 (done).

Can a promise be safely 'swallowed'?

I'm given a promise and am returning it at the end of my function for other code to do more actions after me. A kind of middleware, if you will.
return apiCallPromise;
Lets say for some reason I wish to stop those actions from happening and "swallow" a particular promise. For example by doing the following:
if (promiseShouldBeStopped) return new Promise((resolve) => {})
return apiCallPromise;
This correctly returns a promise, however it never resolves. And so the 'promise chain' has been stopped dead in its tracks.
This seems like an anti-pattern to me as it the promise is left pending forever. Are there any bad effects of this that I should be aware of, or is this a fine technique for "filtering" promises?
Attempt to answer my own question
Does this cause memory issues?
Future code doesn't know that this promise has been filtered out, and so fails to do any "catch" or "finally" cleanup code.
In my case this is not relevant, and I want this code to take care of those errors so that the future code doesn't have to deal with them. (this means I can guarantee that onFulfilled gives the api response, and onRejected only gives an error that is actually unexpected)

clarification about promises in javascript

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 ?
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.
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.

Using Angular Http.Get() synchronously

I have a very simple requirement:
I'm writing a authorization service for an Angular site (Angular 7 it makes a difference).
The service needs a "hasPermission" function which takes a user and a resource name. It makes an Http.Get() call to a backend to determine whether or not the user is authorized to access that resource. When, and ONLY WHEN, the data comes back from the Get() call, it returns true or false.
I have been searching the web for about a week trying to figure out how to do it. My problem is that the Http.Get() returns an observable AND THEN CONTINUES. Which means the function returns before it receives the data back on which to make a decision. The same thing if I use the Http.Get().toPromise() - the function continues as soon as the promise is created.
It seems like every "solution" I read is some variant of "return a promise" or "return an observable". But then it's analagous to "It's turtles all the way down" -in this case, it's promises (or observables) all the way up. At some point there needs to be a method that waits for and returns the data, not a promise of the data or an observable of the data.
I need some way to add a "waitForDone" after creation of the observable or promise and before the function returns its value, but from everything I can find, you can't do that in JavaScript because it's single-threaded.
Note, I can't, as some solutions have suggested, "Just put the code after the http.get(...) in a separate function and call it from success callback" because the code to be execute needs to return from this function.
And async/await doesn't do it, because async turns the whole function into a promise, so, even though the await may wait for the Get() to return the data, the function will still have gone on and returned to the caller before it had the data it needed.
It doesn't seem to me that this is an unusual requirement. While it's nice to be able to issue a request then go do something else while you wait for the data to come back, there have to be times when you MUST HAVE the data before you can do anything else.
Any help is appreciated.
You can use the async-await syntax: instead of
get(someArgs).subscribe(doStuff);
you could put async in the function declaration and then go as follows
const someVal = await get(someArgs).toPromise();
doStuff(someVal); // this line won't execute until get() has resolved the promise
But, fundamentally, it is turtles all the way down. It's syntactic sugar atop of the Promise recipe, and that's what it gets transpiled to (if you transpile it).

Reject and terminate promise on external event

I want to be able to reject and stop the rest of the promise from running if an external event occurs. This is the example usecase:
new Promise((resolve,reject)=>{
websocket.onerror=reject;
//do processing here
websocket.onerror=undefined;
resolve(...);
});
This has the intended effect of rejecting the promise if an error occurs while the promise is running. However, the problem is that the rest of the promise will continue running even if a rejection occurs.
Using async/await the above is not possible at all.
I think one way would be to have every single line of code in a separate promise, and cancelling the chain on an event, but that would be a pain.
However, the problem is that the rest of the promise will continue running even if a rejection occurs.
This is a basic misunderstanding (and you're not alone in it!). There is no "rest of the promise." A promise is just a means of observing the completion of an asynchronous process. It's the process, not the promise, that's continuing.
How you cancel that process (and whether you can) depends entirely on what that process is and whether it provides a means of cancelling it, which is unrelated to promises themselves. You seem to be using a web socket, so you'd need to use the web socket API to cancel whatever you have it doing (or to send a message to the other end to tell it to stop what it's doing).
For instance: Suppose the promise were waiting for a timer (setTimeout) to fire, and would resolve when it did. Then some other thing happens and you no longer want that. Rejecting the promise just rejects the promise, it doesn't have any effect on the timer. You'd need to cancel the timer, too (clearTimeout).
Re your edit:
I think one way would be to have every single line of code in a separate promise, and cancelling the chain on an event, but that would be a pain.
No, the code in the promise executor (the function you pass new Promise) is run synchronously. Again, there's no "rest of the code" to cancel. There may well be asynchronous callbacks in there, or a process the code starts you need to send a cancellation too, but that's not going to require putting every line in its own promise, not at all.
Understanding the answer to this question may help you:
When you create the promise, it is executed synchronously. So this line is executed:
websocket.onerror=reject;
At this point, your code begins to process. If there is an event of websocket error, it is put in the js event loop, but your promise is still executing synchronously. Then you unhook the websocket's error handler, and resolve. The promise will resolve even if there was an error. At this point the call for resolve is also added to js' event loop. Then the next js tick executes, and maybe reject is called, maybe not, but it doesn't matter at this point because you resolved synchronously, and promises never change their minds once they've resolved or rejected.
So the key takeaway here is that creating a promise executes it synchronously. It's not a thread that you can cancel while waiting for other events. The promise' resolution or rejection is executed asynchronously, but that doesn't help you at all.
To cancel a promise, you'll need some pretty basic stuff such as
if(someOtherVariableThatDeterminesCancelation){
reject()
}

Categories

Resources