Exceptions should be used for exceptional conditions. Throwing an exception is basically making the statement, "I can't handle this condition here; can someone higher up on the call stack catch this for me and handle it?"
Returning a value can be preferable, if it is clear that the caller will take that value and do something meaningful with it. This is especially true if throwing an exception has performance implications, i.e. it may occur in a tight loop.
Throwing an exception takes much longer than returning a value (by at least two orders of magnitude).
Exceptions should never be used to implement program logic. In other words, don't throw an exception to get something done; throw an exception to state that it couldn't be done.
First of all, I would disagree with this statement:
Favour exceptions over error codes
This is not always the case: for example, take a look at Objective-C (with the Foundation framework). There the NSError is the preferred way to handle errors, despite the existence of what a Java developer would call true exceptions: @try, @catch, @throw, NSException class, etc.
However it is true that many interfaces leak their abstractions with the exceptions thrown. It is my belief that this is not the fault of the "exception"-style of error propagating/handling. In general I believe the best advice about error handling is this:
Deal with the error/exception at the lowest possible level, period
I think if one sticks to that rule of thumb, the amount of "leakage" from abstractions can be very limited and contained.
On whether exceptions thrown by a method should be part of its declaration, I believe they should: they are part of the contract defined by this interface: This method does A, or fails with B or C.
For example, if a class is an XML Parser, a part of its design should be to indicate that the XML file provided is just plain wrong. In Java, you normally do so by declaring the exceptions you expect to encounter and adding them to the throws
part of the declaration of the method. On the other hand, if one of the parsing algorithms failed, there's no reason to pass that exception above unhandled.
It all boils down to one thing:
Good interface design.
If you design your interface well enough, no amount of exceptions should haunt you.
Otherwise, it's not just exceptions that would bother you.
Also, I think the creators of Java had very strong security reasons to include exceptions to a method declaration/definition.
One last thing: Some languages, Eiffel for example, have other mechanisms for error handling and simply do not include throwing capabilities. There, an 'exception' of sort is automatically raised when a postcondition for a routine is not satisfied.
Best Answer
This is not an anti-pattern. This is a code smell, which is to say that this is the sort of thing you should avoid when it's feasible to do so, but there may be legitimate cases where nothing else does the job.
Yup. This is exactly why the default behavior of Promise.all is to fail fast.
I assume that means you're in a situation where even if some of the promises reject, you can still do something useful with the other promises that resolved successfully. This is definitely not an uncommon situation.
Presumably because that useful thing you can do with however many promises did resolve can only be done...after they've all resolved.
Let's pretend for a moment that the promises represent bank transactions and your UI is going to display either green or red text based on whether the transaction succeeds.
If only some transactions succeed and others fail, you would definitely want to show the successful ones in green and the failed ones in red, rather than "choking" and settling for a single frustratingly uninformative "one or more of your transactions may have failed" message. In that context, I can't imagine anyone objecting to code like this:
which we might "loop over" with a Promise.all at some point.
This is a case where it makes sense for the underlying promise to reject, it makes sense to wait for a set of such promises to finish, and it makes sense to handle failures on a per-promise basis instead of treating all failures as a failure for the whole batch.
But if any of those is not the case in your getAccounts() example, then you should consider alternatives such as making the underlying promise not reject in the first place, reacting to each promise resolution individually instead of waiting on a Promise.all, or simply letting Promise.all fail fast if in your case it is totally okay to ignore the successful ones.
In fact, even the example I just gave doesn't necessarily meet those standards. It's likely you could also handle each transaction promise individually, so the user sees "Transaction 1 succeeded!" and then a few seconds later "Transaction 2 failed!". You could then do a Promise.all over the promises for rendering these messages (which should always succeed unless there's a rendering error) so that you can put some additional message like "All transactions succeeded!" or "3/10 transactions failed!" at the very top.
When thinking about how promises propagate results and errors, I find it often helps to consider the equivalent "normal", "synchronous" or "imperative" non-promise code that returns values and throws/catches exceptions. For your example, that would probably be:
Everything I said above applies to this code as well, though seeing it like this might make it more obvious why it applies. To summarize: this might be legitimate, but it definitely needs justification, and it's definitely worth thinking about whether that justification holds up or if there are cleaner alternatives.