JavaScript Promises - reject vs. throw
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 use reject
.
For example, this won't trigger the catch:
new Promise(function() {
setTimeout(function() {
throw 'or nah';
// return Promise.reject('or nah'); also won't work
}, 1000);
}).catch(function(e) {
console.log(e); // doesn't happen
});
Should I throw an error or return a rejected promise inside an async function?
They are correct.
The call to myCustomFunction
assumes that a promise is returned at all times (.then
and .catch
deal with resolved and rejected promises, respectively). When you throw an error, the function doesn't return a promise.
You could use this to catch the error:
try {
myModule.myCustomFunction(someInput).then(result => {
// carry on
})
.catch(err => {
// do something with the error
})
} catch(err) {
...
}
But as you can see, this results in two error handlers: try/catch
for the synchronously thrown error, and .catch
for any rejected promises that sns.createTopic(someParams)
may return.
That's why it's better to use Promise.reject()
:
module.exports.myCustomFunction = input => {
if (badInput) {
return Promise.reject('failed');
}
return sns.createTopic(someParams).promise()
}
Then, the .catch
will catch both types of errors/rejections.
NB: for newer versions of Node.js (v7.6 and up, I believe), the following will also work:
module.exports.myCustomFunction = async input => {
if (badInput) {
throw new Error('failed');
}
return sns.createTopic(someParams).promise()
}
The key here is the async
keyword. By using this keyword, the function results are wrapped by a promise automatically (similar to what @peteb's answer is showing).
await Promise.reject or throw error to bail out?
It's semantically correct to use throw
in promise control flow, this is generally preferable way to bail out of promise chain.
Depending on coding style, await Promise.reject(...)
may be used to differentiate between real errors and expected rejections. Rejected promise with string reason is valid but throw 'invalid result'
is considered style problem that may be addressed with linter rules, because it's conventional to use Error
instances as exceptions.
The reason why it's important is because string exceptions can't be detected with instanceof Error
and don't have message
property, consistent error logging as console.warn(error.message)
will result in obscure undefined
entries.
// ok
class Success extends Error {}
try {
throw new Success('just a friendly notification');
} catch (err) {
if (!(err instanceof Success)) {
console.warn(err.message);
throw err;
}
}
// more or less
const SUCCESS = 'just a friendly notification';
try {
await Promise.reject(SUCCESS);
} catch (err) {
if (err !== SUCCESS)) {
console.warn(err.message);
throw err;
}
}
// not ok
try {
throw 'exception';
} catch (err) {
if (typeof err === 'string') {
console.warn(err);
} else {
console.warn(err.message);
}
throw err;
}
Since invalid result
is actually an error, it's reasonable to make it one:
throw new TypeError('invalid result');
I am not talking about the promise chain(the whole point of my question), so I don't think the thread JavaScript Promises - reject vs. throw answered my question.
async
function is syntactic sugar for promise chain, so all points that are applicable to promises are applicable to async
as well.
There may be cases when throwing an error is not the same as rejecting a promise, but they are specific to other promise implementations like AngularJS $q
and don't affect ES6 promises. Synchronous error in Promise
constructor results in exception, this also isn't applicable to async
.
Promise constructor with reject call vs throwing error
Is there any difference between using
reject
(inp2
) from thePromise
api, and throwing an error (inp1
) usingthrow
?
Yes, you cannot use throw
asynchronously, while reject
is a callback. For example, some timeout:
new Promise(_, reject) {
setTimeout(reject, 1000);
});
Its exactly the same?
No, at least not when other code follows your statement. throw
immediately completes the resolver function, while calling reject
continues execution normally - after having "marked" the promise as rejected.
Also, engines might provide different exception debugging information if you throw
error objects.
For your specific example, you are right that p1
and p2
are indistinguishable from the outside.
JavaScript Promise: Reject handler vs catch
The difference is that if an error occurs inside resolveHandler it won't be handled by the rejectHandler, that one only handles rejections in the original promise.
The rejectHandler is not used in combination with catch that much, because most of the time we only care about that something went wrong.
Creating only one errorhandler makes the code easier to reason about.
If a specific promise in the chain should handled differently that can be a reason to use a rejectHandler, but i'd probably write a catch().then().catch()
in that case.
Best practice: Promises reject/throw
Obviously, if there's async code involved (such as an database or HTTP request), you can't use throw, since the stack has changed.
That's half the point of promises. Promises are throw safe, they let you use sync facilities like return
and throw
in asynchronous code.
Synchronous:
try {
return fn();
} catch (e) {
// handle error
return recover(e);
}
Promises:
fn().catch(recover);
Or more verbosely:
Promise.resolve().then(function() {
return fn();
}).catch(function(e) {
return recover(e);
});
Related Topics
Remove/Reset Inherited CSS from an Element
Div Square, Width Size Based on 100% Height
Using Queryselectorall(). Is the Result Returned by the Method Ordered
Why Browser Is Returning Empty String on Style.Height ? How to Get Actual Height of an Element
Jquery How to Apply CSS to Selected Text
Mime Type Error with Express.Static and CSS Files
Filling Empty Cells in CSS Grid Layout
Jquery - How to Disable the Entire Page
Getcomputedstyle (Or) $.Css(Map) <-- to Get Every Style Declaration
Programmatically Editing Less (Css) Code with Jquery-Like Selector Syntax
How to Prevent Pull-Down-To-Refresh of Mobile Chrome
Jquery Mobile Prevent Scroll-To-Top Before Page Transition
Jqgrid Viewgridrow Dialog Big Span and Icon
How to Programmatically Detect Size Limit for Data Url
Close a Div by Clicking Outside
How to Set HTML Content into an Iframe