Handling errors in Javascript asynchronous functions at the point of invocation

Adding the keyword async to a function seems to require catching errors within that function. However, there are situations where it doesn't make sense to catch errors and defer them to the caller instead, especially when the context of the function call is unknown (e.g., whether the caller will use res.json(e) or next(e), or neither).

Is there a way to work around this constraint? Is it possible to still use the async keyword for asynchronous operations inside the function and delegate error handling to the caller?

Here's a contrived example to illustrate the issue:

Link to Example Code

try {
    function example(obj = {}) {
        try {
            obj.test = async () => { 
                throw new Error('example error') 
            }
            return obj
        } catch (e) {
            console.log('example outer error')
        }
    }

    let doit = example()
    doit.test() 

} catch (e) {
    console.log('outer error')
}

The above script results in an Uncaught Exception. Removing the async keyword allows it to work, although async may be necessary for other functionality.

Why can't the error be caught when calling doit.test()?

While normally I would adapt and adjust as needed, I found myself unable to answer this question when explaining it to someone else. Can you shed some light on this matter?

Answer №1

What is the reason behind not being able to catch the error when calling doit.test()?

The issue lies in the asynchronous nature of the operation. By the time the code reaches the point where it throws an error, the try-catch block has already executed and completed. As a result, there is no context for the error to be caught.

To address this problem, one can leverage the use of the `catch` callback, which is part of Promises –– since `async` and `await` are essentially syntactic sugar for working with Promises. Simply attach the `catch` method to the returned promise from the `test()` function.

doit.test().catch(()=>{ 
  console.log('Any uncaught exceptions will now be handled here');
}); 

Demo

function example(obj = {}) {
  obj.test = async() => {
    throw new Error('example error')
  }
  return obj;
}

let doit = example()
doit.test().catch(e => {
  console.log('Caught an exception: ', e.message);
});

Answer №2

To capture errors from the test() function, you should use await doit.test().

For a demonstration, visit: https://jsfiddle.net/1tgqvwof/

I have enclosed your code within an anonymous function since await must be contained within an async function.

(async function () {
    try {
        async function example(obj = {}) {
            try {
                obj.test = async () => { // If I remove the async keyword, it works. Otherwise, I am compelled to handle errors here.
                    //try{
                    throw new Error('example error') // I understand that 'example outer error' will not be caught as the context of the returned object is lost
                    //}catch(e){
                    //  console.log("I don't want to catch the error here"), I prefer to defer it to the caller
                    //}
                }
                return obj
            } catch (e) {
                console.log('example outer error')
            }
        }

        let doit = example()
        await doit.test() // Why doesn't 'outer error' catch this?

    } catch (e) {
        console.log('outer error')
    }
})();

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Make sure to include the "active" class in the pager once the slider begins

After coming across this fiddle, I noticed that it closely resembles the task I am working on. However, there is one issue - currently, only the first item has an active class when the slider autostarts. The next or previous items do not receive the acti ...

How to change a string into an object in JavaScript that includes a colon symbol

Can anyone suggest the most efficient way to convert the string var xx = "website:https://google.com"; into a dictionary format like {website:"https://google.com"}? Usually, I use str.split(":"), but in this case, there are multiple colons. Would using t ...

Ensure prototype is easily accessible within vuex

Within my app.js file, I implemented a functionality to enable translation in Vue: Vue.prototype.trans = string => _.get(window.i18n, string); This feature works perfectly when used in my Vue files: {{ trans('translation.name') }} However, ...

"Utilizing NodeJS in conjunction with socket.io and PostgreSQL's LISTEN feature

My goal is to create a frontend that can detect events whenever a specific table in my Postgres database is modified. The Postgres events are triggering correctly and I am able to transmit them through the Socket.io connection. However, I am experiencing ...

I've encountered an issue with React Router where it is only displaying a blank page even after I have set up my

Check out app.js here. After opening the page, all I see is a blank white screen. There aren't any visible errors or indications of what might be causing this issue. ...

Innovative form creation using Vue.js

My interactive form allows users to input an item, quantity, and cost per item like this: <form @submit.prevent="submit"> <div class="form-group" v-for="(input,k) in inputs" :key="k"> <input ty ...

JQuery form not triggering the submit event

Currently, I am facing some issues with my code while trying to trigger on submit event on a form and validate it. The main problems I encountered are that the onsubmit event is not being triggered, and the input field of type email is not validated proper ...

javascript href clears Internet Explorer webpage

I noticed a strange issue with my HTML page. In Internet Explorer, when I click on the link, it displays the return value on a blank page. However, in Chrome, it simply executes the function without affecting the page appearance. Is there a way to make I ...

Sending an Array of Data to Jquery

One of the buttons in my code looks like this: <button id='abc' value=['fred', 26]></button> I am looking for a way to retrieve the two values using JQuery's .val() function. My attempt $("#abc").val()[0] only return ...

Slide feature in Drupal Views allows you to create dynamic

This is the design I currently have: https://i.stack.imgur.com/P6spc.jpg For example, when you click on the "Structure" header, it opens up the contents and shows an image. I have created a content type and installed Views. I have separated the image, h ...

Filtering options in a dropdown box with jQuery

I have implemented a feature where the content of one select box is filtered based on the option selected in another select box. Below is the code snippet that achieves this functionality: // Filter content based on the selected option in a region select ...

Extending a Sub-Object in JavaScript

I'm attempting to include new attributes to the sub-object within object1. However, I am facing issues with it being overwritten. const object1 = { a: 1, b: 2, c: 3, sub: { e: 1, f: 2 } }; const object2 = Object.assign({ j: 4, ...

Creating a Toggle Function for the Hamburger Menu in JavaScript

Struggling to create a responsive navbar with a hamburger menu toggle. Followed an online tutorial and managed to get everything working, except for the toggle functionality of the menu. Clicking on the icon does nothing. Being new to this, I'm not su ...

Combining the functionality of a click event

Is it possible to combine these two functions in a way that ensures when '#css-menu' is shown, '.menu' becomes active, and vice versa? $('.menu').click(function() { $('#css-menu').toggleClass('shown hidden& ...

store events in a MySQL database using a servlet callback and display them on a full calendar

Hey there! I recently started using the full-calendar jQuery plugin and successfully integrated it into a JSP page. The events on the calendar are loaded from a MySQL database by calling a servlet that generates a JSON array of retrieved elements. Now, I& ...

Combine going to an anchor, performing an AJAX request, and opening a jQuery-UI accordion tab all within a

My goal is to have the user click on the hyperlink below, which will (1) anchor to #suggestions, (2) navigate to the url suggestions.php?appid=70&commentid=25961, and (3) open the jquery-ui accordion #suggestions. However, I am facing an issue where c ...

When converting to TypeScript, the error 'express.Router() is not defined' may

Currently, I am in the process of converting my express nodejs project from JavaScript to TypeScript. One of the changes I've made is renaming the file extension and updating 'var' to 'import' for "require()". However, there seems ...

Assistance required: Click on the button to select and copy all text within the specified paragraph ID

Hey there! I've got a div with a dropdown menu that reveals text and images based on the selected option. What I want to achieve is having a button that allows users to copy all the content inside the div. Below is my sample code for the div dropdown ...

What is the best way to place a background image at the top left and bottom right corners of an HTML element?

I have a paragraph and I would like to visually mark the beginning and end of the paragraph for the user. I have successfully displayed a background image in the upper left corner, but I am unsure how to position the background image in the lower right co ...

Unleashing the power of RollupJs: A guide to dynamically bundling modules and objects

Is there a way to dynamically bundle a module/object into my RollupJs output file? I have experimented with various options without success in achieving the desired result. Below is a brief sample project that demonstrates what I am trying to achieve. The ...