I have a function, downloadAsync(), that returns a CommonJS promise (using Q). It can fail in two ways:
- The file can already be downloaded, in which case we know immediately.
- The download process could fail, in which case we know some time later.
In case (1), since I know before anything asynchronous happens, I could throw an exception. In case (2), I’d have to reject the promise.
My question is, should my API be uniform and always signal error by rejecting the promise? Or should I throw exceptions for immediately-determinable invalid state conditions? As another example, if the user passed me an invalid argument, it would seem much more sensible to throw an error than to reject the promise.
Some clarity on how “exceptional” promise rejection really is would be great, as well; does usage there map one-to-one with exception usage practices, or do we use it for non-exceptional failure as well?
If you want to know what you should do when your function (which implements Q) should do when presented invalid input that could be detected synchronously, I looked at the source code for Q, to see what Q did.
Here’s an example.
When Q is presented with invalid input, Q invokes the resolver with a rejection object. Therefore you could be justified in having your API behave similarly, rather than trying to modify the behavior of the underlying library.
Plus, look at it from a standpoint of anyone who consumes your API. Do they want to develop and maintain two exception handling code paths, or one?