Reject and terminate promise on external event - javascript

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()
}

Related

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.

Javascript Promise behavior after the System resume from sleep mode

What's expected to happen with running Javascript promises when my system sleeps and then get back to the resume state?
Let's suppose that I have a Javascript application that is running and there are some promises doing their asynchronous work (as requesting data from a remote endpoint), so I'm put my OS on sleep mode and go away. After some time, I get back and resume my system. Would those promises continue running after that? Can I assume that either the "then" or "catch" will be called for each of them or is it possible to get some zombie promises that will never return?
It would be great if the answer comes together with some source to basis it =)
Yes of course you could have Promises that never resolve. here you have a Promise that never resolve.
const promiseThatNeverResolve = new Promise((resolve, reject) => {})
Though, they are implementation errors... in general asynchronous activities have some timeout to take a determination of the resolution or rejection of the promise.
In any case, I think it has some merit to do the test of the scenario you were mentioning and see what is happening and reason about it.
If you execute the code below and put your laptop to sleep for less than 50 seconds and then awake it. You will see that the Promise resolve OK showing "finished OK". Laptop was able to save the current state of the memory before going to sleep and when was awaken to restart with the same state. This means Promise was saved in Pending state and recover in Pending state. Same thing for node event loop, processes and so on.
But even more... it would work if you wait for more than 60 seconds. The laptop awakes with the same state of event loop, stack and so on (that had before going to sleep), like a time machine that freezes the time and resume it as it no time has passed... so resolve function is still scheduled to be executed. And Promise will still be pending. Then, due to the implementation of setTimeout, it will call the resolve function, at least one, no matter how much time would have passed. If the implementation would have decided to throw an exception then Promise will be rejected and you will see the log of the catch().
It is interesting to observe that after awakening the laptop for more than 60 seconds, it took another 10 seconds to show the successful result... Probably while restoring the internal memory state.
const myProm = new Promise((resolve, reject) => {
setTimeout(resolve, 50000)
})
myProm.then(()=>console.log('finished OK')).catch(()=>console.log('failed'))
This has nothing to do with promises.
There are some promises doing their asynchronous work (as requesting data from a remote endpoint)
Promises do not do any work. Promises are only a notification mechanism (and a bit more), they do represent an asynchronous result not the work.
So it depends on that work which you're doing, for whose result you got a promise, and how that API (like your network request) handles being suspended by the operating system. Assuming there are no mistakes in the driver code or library that your JS runtime's host objects exposes, they should be getting an error about the cancelled request. Even if the error code was ignored, any reasonably well-defined API for remote access should at some point run into a timeout, and invoke a callback that will then resolve your promise.
If you are talking about the system being suspended between the time a promise was resolved and the time the then handlers get called, yes the handlers got scheduled and the JS runtime is responsible for normal continuation of the program.

How exactly is a promise's value updated?

Let's suppose that a fetch request is executed at 2ms. The program keeps running. Then, at 100ms the request has been completed, but the program hasn't finished its execution.
1. At this point, does the browser actually update the value in the Promise object even though the program hasn't finished yet, or does this have to be done in Javascript's thread, when the call stack is empty?
2. How do the onFulfilled and onRejected callbacks get enqueued to the Job queue?
As far as I know, they do so when the Promise's state changes, but how exactly is this done?
Is the browser behind the scenes "watching" for changes in the object and enqueuing the callback immediately, or is it Javascript that does it when finishing executing synchronous code?
EDIT: I was told in a course that, roughly speaking, what happened under the hood was that the Promise object's property "value" was updated as soon as the request was successfully completed (even if the program was still running), and immediately triggered two things: a change on the Promise's state, and the callback in onFulfillment array to be enqueued in the microtask queue (assuming one was added using then). Is this possible? Does the Promise object actually get modified outside Javascript, or is this done when the program finishes its execution?
Please correct me if I make any mistakes.
Assuming that the fetch call will succeed without error, at 100ms when the Request has been correctly sent and the Body is being streamed, a new fetch task is enqueued in the Networking task source which will process the response. This final algorithm is the one responsible to resolve the Promise returned by window.fetch().
So if at 100ms, the browser has something else to do, it will continue to do whatever it was. If when it's done doing that, it feels it has a more important task to do (e.g UI event?), then it will do that before. When it will proceed that fetch task, it will resolve the Promise, and doing so, it will queue a microtask to execute your callback, right after that task is done processing (i.e synchronously here).

Protractor, when should I use then() after a click()

I'm running an Angular app and when testing on protractor a click(), I don't know when should I resolve the promise with a then().
I found this on Protractor API:
A promise that will be resolved when the click command has completed.
So, should I use click().then() in every click?
So, should I use click().then() in every click?
Definitely not.
It's not needed because Protractor/WebDriverJS has this mechanism called "Control Flow" which is basically a queue of promises that need to be resolved:
WebDriverJS maintains a queue of pending promises, called the control
flow, to keep execution organized.
and Protractor waits for Angular naturally and out-of-the-box:
You no longer need to add waits and sleeps to your test. Protractor
can automatically execute the next step in your test the moment the
webpage finishes pending tasks, so you don’t have to worry about
waiting for your test and webpage to sync.
Which leads to a quite straight-forward testing code:
var elementToBePresent = element(by.css(".anotherelementclass")).isPresent();
expect(elementToBePresent.isPresent()).toBe(false);
element(by.css("#mybutton")).click();
expect(elementToBePresent.isPresent()).toBe(true);
Sometimes though, if you experience synchronization/timing issues, or your app under test is non-Angular, you may solve it by resolving the click() explicitly with then() and continue inside the click callback:
expect(elementToBePresent.isPresent()).toBe(false);
element(by.css("#mybutton")).click().then(function () {
expect(elementToBePresent.isPresent()).toBe(true);
});
There are also Explicit Waits to the rescue in these cases, but it's not relevant here.
Yes, you should.
Maybe right now it's not necessary, but maybe in next versions it is.
So, if click return a promise, you should use it.
http://www.protractortest.org/#/api?view=webdriver.WebElement.prototype.click

Categories

Resources