Can errors from a non-awaited async call be caught, sent to an original encapsulating try/catch, or raise an uncaught exception?
Here's an example of what I mean:
async function fn1() { console.log('executing fn1'); } async function fn2() { console.log('executing fn2'); throw new Error('from fn2'); } async function test() { try { await fn1(); fn2(); } catch(e) { console.log('caught error inside test:', e); } } test();
In this scenario, the error thrown from fn2
will be swallowed silently, and definitely not caught by the original try/catch
. I believe this is expected behavior, since fn2
is most likely being shoved off to the event loop to finish at some point in the future, and test
doesn't care when it finishes (which is intentional).
Is there any way to ensure that errors are not accidentally swallowed by a structure like this, short of putting a try/catch
internal to fn2
and doing something like emitting an error? I would even settle for an uncaught error without knowing how to catch it, I think -- I don't expect thrown errors to be typical program flow with what I am writing, but swallowing errors makes it relatively annoying to debug.
Side note, I'm using Babel to transpile the code using the babel-runtime transform, and executing it with node.
In this way, an async function without an await expression will run synchronously. If there is an await expression inside the function body, however, the async function will always complete asynchronously. Code after each await expression can be thought of as existing in a .then callback.
Async function without await insideWe can declare a function as async without using any await . In this case, the execution is not paused and your code will be executed in a non-blocking manner (asynchronous - no waiting). It is the same as not declaring that same function with async .
There are a few alternative async/await transpilers to Regenerator, which take async code and attempt to convert to more traditional . then and . catch notation. In my experience, these transpilers work pretty well for simple functions, which await then return , perhaps with a try/catch block at most.
Dealing with unhandled rejected native promises (and async/await uses native promises) is a feature supported now in V8. It's used in the latest Chrome to output debugging information when a rejected promise is unhandled; try the following at the Babel REPL:
async function executor() { console.log("execute"); } async function doStuff() { console.log("do stuff"); throw new Error("omg"); } function handleException() { console.error("Exception handled"); } (async function() { try { await executor(); doStuff(); } catch(e) { handleException(); } })()
You see that, even though the exception from doStuff()
is lost (because we're not using await
when we call it), Chrome logs that a rejected promise was unhandled to the console:
This is also available in Node.js 4.0+, though it requires listening to a special unhandledRejection
event:
process.on('unhandledRejection', function(reason, p) { console.log("Unhandled Rejection at: Promise ", p, " reason: ", reason); // application specific logging, throwing an error, or other logic here });
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With