I have read several articles on this subject, but it is still not clear to me if there is a difference between Promise.reject
vs. throwing an error. For example,
Using Promise.reject
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
return Promise.reject(new PermissionDenied());
}
});
Using throw
return asyncIsPermitted()
.then(function(result) {
if (result === true) {
return true;
}
else {
throw new PermissionDenied();
}
});
My preference is to use throw
simply because it is shorter, but was wondering if there is any advantage of one over the other.
Another important fact is that
reject()
DOES NOT terminate control flow like areturn
statement does. In contrastthrow
does terminate control flow.Example:
vs
Yes, the biggest difference is that reject is a callback function that gets carried out after the promise is rejected, whereas throw cannot be used asynchronously. If you chose to use reject, your code will continue to run normally in asynchronous fashion whereas throw will prioritize completing the resolver function (this function will run immediately).
An example I've seen that helped clarify the issue for me was that you could set a Timeout function with reject, for example:
The above could would not be possible to write with throw.
In your small example the difference in indistinguishable but when dealing with more complicated asynchronous concept the difference between the two can be drastic.
There is no advantage of using one vs the other, but, there is a specific case where
throw
won't work. However, those cases can be fixed.Any time you are inside of a promise callback, you can use
throw
. However, if you're in any other asynchronous callback, you must usereject
.For example,
won't trigger the catch, instead you're left with an unresolved promise and an uncaught exception. That is a case where you would want to instead use
reject
. However, you could fix this by promisifying the timeout:An example to try out. Just change isVersionThrow to false to use reject instead of throw.
TLDR: A function is hard to use when it sometimes returns a promise and sometimes throws an exception. When writing an async function, prefer to signal failure by returning a rejected promise
Your particular example obfuscates some important distinctions between them:
Because you are error handling inside a promise chain, thrown exceptions get automatically converted to rejected promises. This may explain why they seem to be interchangeable - they are not.
Consider the situation below:
This would be an anti-pattern because you would then need to support both async and sync error cases. It might look something like:
Not good and here is exactly where
Promise.reject
( available in the global scope ) comes to the rescue and effectively differentiates itself fromthrow
. The refactor now becomes:This now lets you use just one
catch()
for network failures and the synchronous error check for lack of tokens: