How to Wrap an Await/Async Try/Catch Block to Every Function

Is there a way to wrap an await/async try/catch block to every function?

Yes, you can easily write such a wrapper for asynchronous functions as well - just use async/await:

function wrapper(f) {
return async function() {
// ^^^^^
try {
return await f.apply(this, arguments);
// ^^^^^
} catch(e) {
customErrorHandler(e)
}
}
}

Or you use promises directly, like in this example that is more tailored to express (especially with the number of parameters):

function promiseWrapper(fn) {
return (req, res, next) => {
fn(req, res).catch(next);
};
}

Does async function try catch block can wrap a called async function that also may throw an error?

Generally, you want to catch errors at a point where you can do something useful in response to the error. Often, this is not the point where the API is called, but somewhere further up the call stack. Allowing errors to naturally propagate upwards to where they can be handled reasonably is a fine idea.

For example, in a real application, if there's a catch block which is composed solely of a console.log, that's often (not always) an indication that the error should be caught somewhere else. When there's an error, one will often want to inform the user that there was a problem, so the following sort of pattern is very common:

getAPI()
.then(populateWithResults)
.catch((error) => {
const div = document.querySelector('.errors').appendChild(document.createElement('div'));
div.textContent = 'There was an unexpected error: ' + error.message;
});

where getAPI does no catching of its own, but simply allows the caller to handle possible errors - similar to what your getJSON function is doing.

Usually you'll only want one point where an error is caught, but occasionally you might want to catch it in multiple places - for example, perhaps a sub-component wants to do something in particular when an error is encountered, but it also wants to notify the callers that there's a problem. In such cases, re-throwing the error could look like:

const makeSubComponent = () => {
const componentContainer = document.querySelector('.container');
const populateSubComponent = () => {
// ...
};
return getAPI()
.then(populateSubComponent)
.catch((error) => {
componentContainer.textContent = 'Something went wrong...'
throw error; // Inform the caller of makeSubComponent of the error
});
};

allowing both makeSubComponent and its caller to deal with possible problems.

try/catch blocks with async/await

Alternatives

An alternative to this:

async function main() {
try {
var quote = await getQuote();
console.log(quote);
} catch (error) {
console.error(error);
}
}

would be something like this, using promises explicitly:

function main() {
getQuote().then((quote) => {
console.log(quote);
}).catch((error) => {
console.error(error);
});
}

or something like this, using continuation passing style:

function main() {
getQuote((error, quote) => {
if (error) {
console.error(error);
} else {
console.log(quote);
}
});
}

Original example

What your original code does is suspend the execution and wait for the promise returned by getQuote() to settle. It then continues the execution and writes the returned value to var quote and then prints it if the promise was resolved, or throws an exception and runs the catch block that prints the error if the promise was rejected.

You can do the same thing using the Promise API directly like in the second example.

Performance

Now, for the performance. Let's test it!

I just wrote this code - f1() gives 1 as a return value, f2() throws 1 as an exception:

function f1() {
return 1;
}

function f2() {
throw 1;
}

Now let's call the same code million times, first with f1():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f1();
} catch (e) {
sum += e;
}
}
console.log(sum);

And then let's change f1() to f2():

var sum = 0;
for (var i = 0; i < 1e6; i++) {
try {
sum += f2();
} catch (e) {
sum += e;
}
}
console.log(sum);

This is the result I got for f1:

$ time node throw-test.js 
1000000

real 0m0.073s
user 0m0.070s
sys 0m0.004s

This is what I got for f2:

$ time node throw-test.js 
1000000

real 0m0.632s
user 0m0.629s
sys 0m0.004s

It seems that you can do something like 2 million throws a second in one single-threaded process. If you're doing more than that then you may need to worry about it.

Summary

I wouldn't worry about things like that in Node. If things like that get used a lot then it will get optimized eventually by the V8 or SpiderMonkey or Chakra teams and everyone will follow - it's not like it's not optimized as a principle, it's just not a problem.

Even if it isn't optimized then I'd still argue that if you're maxing out your CPU in Node then you should probably write your number crunching in C - that's what the native addons are for, among other things. Or maybe things like node.native would be better suited for the job than Node.js.

I'm wondering what would be a use case that needs throwing so many exceptions. Usually throwing an exception instead of returning a value is, well, an exception.

Can I use multiple 'await' in an async function's try/catch block?

Using one try/catch block containing multiple await operations is fine when waiting for promises created on the right hand side of the await unary operator:

The await operator stores its parent async functions' execution context and returns to the event loop. Execution of the await operator resumes when it is called back with the settled state and value of its operand.

Upon resumption, await restores the previously saved execution context and returns the operand promise's fulfilled value as the result of the await expression, or throws the rejection reason of a rejected operand.

The try/catch block invocation is part of the execution context both before and after being saved and restored. Hence multiple await operations do not disturb the behavior of an outer try block they share. The catch block will be invoked with the rejection reason of any promise awaited in the try block that is rejected.

If however code awaits multiple existing promises in the same try/catch block and more than one of the promises rejects, an uncaught promise rejection error is generated for all but the first rejection. Thanks to @EyolRoth for supplying this caveat, please read his entire answer in conjunction with this one.

Async/Await nested try/catch

What I usually do with async/await to avoid the nesting is to return tupels of [result, error] instead of try/catch blocks.

So in this case my code would look something like this:

async function foo() {
const response = await postRequest();

if (response.ok) {
return [response, null];
}

return [null, "error"];
}

async function bar() {
const response = await anotherReq();

if (response.ok) {
return [response, null];
}

return [null, "error"];
}

// call functions
const [res, err] = await foo();

if (err) {
const [res, err] = await bar();
}

Will try-catch catch an error if the function inside of it doesn't have an await in front of it?

No. Without an await the calling function will not go to sleep and wait for the promise to resolve or error. It will continue running to its own completion.

Later, when the promise errors, the error will be unhandled.

Why is try {} .. catch() not working with async/await function?

You need to await errorTest

const callFunction=async()=>{
try{
const result = await errorTest()
}catch(err){
console.log(err)
}
}
callFunction ()

Note that the await errorTest() function has to also be in an async function. That's why I put it inside callFunction ()

Another Option

const errorTest = async() => { 
try{
const result = await $.get("http://dataa.fixer.io/api/latest?access_key=9790286e305d82fbde77cc1948cf847c&format=1");

console.log(result)
}catch(err){
console.log(err)
}
}

Async/Await while avoiding the Try/Catch block?

You have to choose. Using try, catch block, or use promises. The reason for async/await exist, is for people who do not like promises, and prefer cleaner code.

If you don't want both, you can use

https://nodejs.org/api/process.html#process_event_uncaughtexception

or

https://nodejs.org/api/process.html#process_event_unhandledrejection



Related Topics



Leave a reply



Submit