Rejecting and then Resolving a Q Promise - javascript

I have seen code that looks like this:
var defer = Q.defer();
// do something, here's the callback
if (err) {
defer.reject({err: err})
}
defer.resolve({success: data});
// close callback
return defer.promise;
If a promise is first rejected, and then resolved, it appears that the "rejection" remains.
When I first saw this pattern, I was inclined to suggest to wrap the resolve inside an else, but since it works as is, is this an acceptable pattern?
Could there ever be a problem with rejecting and then resolving a promise?
It appears that if you resolve and then reject, the resolution remains. So whichever happens first, is what "sticks"?

So whichever happens first, is what "sticks"?
Yes, exactly. The state of a promise is immutable once it is settled (either fullfilled or rejected). So no, there can't be a problem occurring here, the promise is "locked" as rejected if the rejection happens first.
However, think about if a single else doesn't actually improve your code quality. Less code lines don't necessarily improve code readability! I'd say it would, because it's much easier to quickly understand what happens if you see an if/else. What if someone else has to look at your code, and they also at first don't know that promises are immutable after settling?
Chapter 3 of "You Don't Know JS (async & performance)" is an excellent resource to more fully grasp promises. And so is the Promises A+ specification, which Q conforms to. The latter is more of an "objective source of truth", but it's harder to read (well, it's a spec).

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.

Get value of resolved Promise in sync

If we know that a Promise is definitely resolved, how can we access the value and if we can't, why not?
let a = Promise.resolve(123);
console.log(a.value); // ???
The following does not work- it prints "First, Last, 123"
console.log("First");
Promise.resolve(123).then(console.log);
console.log("Last");
I'm asking how to get the value of an already resolved Promise synchronously and if that's not possible, why not?
No, it is not possible to do this. This is by design.
The Promise A+ specification is meant to be used as a simple, consistent way to deal with asynchronous operations. One of the constraints is that passing a new callback on to then() on an already resolved promise will always execute on a later tick in the event loop, so things are consistent.
Adding a secondary way to inspect promise results would not have been impossible. It would probably have been quite easy to do so, but there's at least 2 problems with adding this to the specification:
If you're looking to build a specification, you want it to be as simple as possible. The specification itself actually only defines the then() function.
By adding this feature, you're opening the door to hordes of developers getting even more confused about something that's already hard to grok.
Promises and asynchronous operations are hard for people to understand. I see questions here daily about promises and not 'getting' it. If non-async way to access promise results would be added to the default promise, I'd imagine that this would be an even larger amount. It's good to try and enforce 'the right way' of doing things.
However, this decision is not simply made for you. You're not stuck there. You can very easily build your own version of a promise that has this feature, and still works with existing promises. As long as your object has a then() function that behaves according to Promises/A+ you can do with the rest of the object whatever you want.
Promises are always asynchronous in JS.
If you're confident that promise is going to resolve then you can access it with .then method.
a.then(function(value) {
console.log("First");
console.log(value);
console.log("Last");
// expected output: 123
});
Variable a will lookalike below if it is console.log
Promise {<resolved>: 123}
__proto__: Promise
[[PromiseStatus]]: "resolved"
[[PromiseValue]]: 123
For error handling, you can error block as mentioned in MDN docs.
Promise.resolve(123).then(function(value) {
console.log(value);
}
Take a look on this

Structuring "then" handler for both sync/async condition

I am struggling to fix what I think is a very simple jQuery promise problem. In effect, I need to bypass a 'then' in certain circumstances within a promise chain when a previous promise discovers it won't fire asynchronously.
I have a chunk of code (the actual, runtime code is too long to repost here coherently - apologies/mea culpa in advance) for which the "then" portion may run code that will fire asynchronously, or will complete immediately and return - no async execution.
***This has been resolved. In digging through the code, I happened to discover a spot where a promise was not being properly resolved in the no-files condition. This has fixed the problem. Thanks for the keen eyes to #Bergi that indicated something was really awry.
The overarching structure of the code is in this fashion:
****Edited to correct improper call to DisableProgress**
function writeData(){
EnableProgress('Starting upload')
.then(writeRecord)
.then(uploadFiles)
.then(DisableProgress);
}
function uploadFiles(){
var deferred = $.Deferred();
if (fileUploadList.length==0){
deferred.resolve();
} else {
//perform async upload
}
return deferred.promise();
}
The problem is this: when uploadFiles detects no files to upload (a perfectly legitimate situation), no async process occurs; the promise is resolved before it is returned, and the 'then' portion that calls 'DisableProgress' never fires. (There are actually other calls in this chain that fired but are eliminated here for clarity's sake)
I thought about putting in a brief setTimeout within the uploadFiles routine to "force" the async execution in the event there were no files to upload, but that seemed an absurd hack to me. Surely there's an obvious/better way I'm simply overlooking. I've searched Google about issues revolving around resolving a promise prior to its return, but I've not seen (or recognized?) anything on point. I think I'm at a point where I can't see the trees for the forest - I'm making it too complicated. What is my error?

Do promises in AngularJS catch every exception/error?

I've inherited a codebase at work that contains a dozen or so examples of the following pattern:
var promise = null;
try {
promise = backendService.getResults(input);
}
catch (exception) {
console.err(exception);
}
if (promise !== null) {
promise.then(function (response) {
// do stuff
})
.catch(function (error) {
console.err(error);
});
}
Where backendService is an Angular service that in turn calls a REST service through $http.
So here's my question: is that try/catch really necessary? Will there ever be any scenario where a particular error/exception is thrown that the promise's .catch fails to catch?
This has been the subject of a bit of debate on the team all morning, and the only resolution we've come up with is that we don't think it's necessary, but (a) changing it breaks the tests that were written alongside it (which would also need to be changed), and (b) well... it's defensive coding, right? It's not a Bad Thing.
The merits of actually bothering to refactor it into oblivion when there are more important things to do aren't what I'm asking about, though. I just want to know if it's a reasonable pattern when promises are being passed around like this (in AngularJS specifically, if that makes a difference), or just paranoia.
Do promises in AngularJS catch every exception/error?
No. Only exceptions that are thrown from inside then/catch callbacks are automatically caught. All errors happening outside of them will need to be handled explicitly.
Will there ever be any scenario where a particular error/exception is thrown that the promise's .catch fails to catch?
Yes. That backendService.getResults(input) call might not return a promise, but it can throw an exception. Or it doesn't even get that far when backendService is null, and you'll get a ReferenceError or .getResults is not a function and you'll get a TypeError.
is that try/catch really necessary?
Not really. In the latter case, that your code has a grave mistake, you probably don't care to throw and crash. The former case, that backendService.getResults(input) throws, is heavily despised. Asynchronous functions should never throw but only return promises - exactly for the reason that you don't have to write two error handling statements then.
well... it's defensive coding, right? It's not a Bad Thing.
Yeah, pretty much. But it is questionable here. A synchronous exceptions is really unexpected here, not just a service whose failure can be handled. The logging message in the catch block should signify that.
Notice that it also isn't defensive enough. It doesn't catch the probably more likely mistake where getResults() does return, but something that is not a promise. Calling .then() on that might throw. Similarly, the if (promise !== null) is dubious, as it hides when null is returned erroneously (we really could need try-catch-else here).
is that try/catch really necessary?
Not really. As long as your backendService.getResults() returns a promise. Like return $http(...)
Will there ever be any scenario where a particular error/exception is
thrown that the promise's .catch fails to catch?
I don't think so, since any error will be a rejected promise, it will fall into your .catch() handler
well... it's defensive coding, right? It's not a Bad Thing.
It depends... Javascript try/catch is has some performance issues. So if you're using just for the sake of making sure, you could remove it :)
Take a further look at try-catch discussion here if you wish: Javascript Try-Catch Performance Vs. Error Checking Code

Categories

Resources