JavaScript: Don't throw exceptions from async functions
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 throw synchronous exceptions when encountering fatal errors.
So avoid this:
Copyfunction 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:
Copytry { 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:
Copyfunction 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:
Copyfunction 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
:
Copyasync 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:
Copyfunction 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+ Archive 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 Archive
Does your version of Ruby on Rails still receive security updates?
Rails LTS provides security patches for unsupported versions of Ruby on Rails (2.3, 3.2, 4.2 and 5.2).