This case cannot happen when you write an async function()
instead of returning promises explicitly.
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.
The full story
When your function returns a promise ("async function"), try not to throw synchronous exceptions when encountering fatal errors.
So avoid this:
function foo(x) {
if (!x) {
throw "No x given"
} else
return new Promise(function(resolve, reject) {
...
});
}
}
It's hard to handle errors when calling foo
, since we need to handle both a synchronous throw
and an asynchronous rejection. Look how much code we need to handle failures of the foo()
above:
try {
function onFulfilled() { ... }
function onRejected() { // handle async failure }
foo(x).then(onFulfilled, onRejected);
} catch (e) {
// handle synchronous failure
}
Instead you should signal an error by returning a rejected promise:
function foo(x) {
if (!x) {
return Promise.reject("No x given")
} else
return new Promise(function(resolve, reject) {
...
});
}
}
Now your caller only needs to handle async failure:
function onFulfilled() { ... }
function onRejected() { // handle async failure }
foo(x).then(onFulfilled, onRejected);
Converting exceptions to rejected promises
If you have an existing function that throw
s synchronous errors, and you want to convert all these throw
s to rejected promises, you can make the function async
:
async function foo() {
throw "error"
}
foo() // returns Promise.reject("error")
await foo() // throws "error"
As an alternative you can use the behavior that exceptions thrown in promise callbacks will automatically be caught and converted to a rejected promise instead. That means if you really want to throw
from foo()
(or if you're calling another function that throws) you can wrap your code into the callback of a resolved promise:
function foo(x) {
var promise = Promise.resolve();
return promise.then(function() {
if (!x) {
throw "No x given"
} else
return new Promise(function(resolve, reject) {
...
});
}
});
}
This behavior is in all Promises/A+ Show archive.org snapshot compatible implementations like native promises, jQuery 3+ deferreds or Bluebird. Deferreds in jQuery 1 and 2 do not have this behavior.
Read more
Promise-based functions should not throw exceptions Show archive.org snapshot