Handling Errors in Asynchronous Functions with JavaScriptLet's explore the best practices for

I am a beginner in javascript and recently delved into async/await. After going through various resources, I gained a basic understanding. However, while experimenting with some code examples, I encountered unexpected results which left me puzzled about where I went wrong.

Code:

var colors = ["RED", "GREEN", "YELLOW"];

const getColor = async () => {
  var value = "";
  colors.forEach((color) => {
    value = value + color + " ";
  });
  return value;
};


const middleware = async () => {
  addColor(null)
    .then(() => {
      getColor().then((result) => {
        console.log(result);
      });
    })
    .catch((err) => {
      console.log(err.message + " at middleware");
    });
};

const addColor = async (color) => {
  validateColor(color)
    .then(() => {
      console.log("Adding data");
      colors.push(color);
    })
    .catch((err) => {
      console.log(err.message + " at add color");
      throw err;
    });
};

const validateColor = async (color) => {
  if (color == null) {
    throw new Error("Color cannot be empty");
  }
};

middleware();



Upon executing the middleware function, instead of only displaying the error message as expected, the output included the names of colors as well. Output:

https://i.sstatic.net/YfIPM.png

I am perplexed as to why the code inside then() is being executed even when addColor() throws an error. Furthermore, it's puzzling why the catch block within middleware() is not being triggered.

Answer №1

When it comes to validateColor() and addColor(), they both generate Promise objects but are independent of each other. If you tweak addColor() to instead return the Promise from validateColor(), your code will function as intended:

    var colors = ["RED", "GREEN", "YELLOW"];
    
    const getColor = async () => {
      var value = "";
      colors.forEach((color) => {
        value = value + color + " ";
      });
      return value;
    };
    
    
    const middleware = async () => {
      addColor(null)
        .then(() => {
          getColor().then((result) => {
            console.log(result);
          });
        })
        .catch((err) => {
          console.log(err.message + " at  middleware");
        });
    };
    
    const addColor = async (color) => {
      return validateColor(color)
        .then(() => {
          console.log("Adding data");
          colors.push(color);
        })
        .catch((err) => {
          console.log(err.message + " at add color");
          throw err;
        });
    };
    
    const validateColor = async (color) => {
      if (color == null) {
        throw new Error("Color cannot be empty");
      }
    };
    
    middleware();

Your async functions wrap the return values in a Promise. Consequently, both validateColor() and addColor() will unknowingly create distinct Promises unless addressed. In contrast, by having addColor send back the same Promise that validateColor() generates, there is no additional separate Promise formed; the original Promise is passed back to middleware(). As this Promise contains the pending error thrown in validateColor(), the .catch() block will execute.

Answer №2

If I had to sum it up in one sentence, I would say that every async function needs to include a return promise statement - here is the corrected code.

var colors = ["RED", "GREEN", "YELLOW"];

const getColor = async () => {
  var value = "";
  colors.forEach((color) => {
    value = value + color + " ";
  });
  return Promise.resolve(value);
};


const middleware = async () => {
  return addColor(null) 
    .then(() => {
      getColor().then((result) => {
        console.log(result);
      });
    })
    .catch((err) => {
      console.log(err.message + " at middleware");
    });
};

const addColor = async (color) => {
  return validateColor(color)
    .then(() => {
      console.log("Adding data");
      colors.push(color);
    })
    .catch((err) => {
      console.log(err.message + " at add color");
      throw err;
    });
};

const validateColor = async (color) => {
  if (color == null) {
    throw new Error("Color cannot be empty");
  }
  Promise.resolve(true);
};

middleware();

Explanation:

Simply put, an async function must return a promise in order for await statements to work effectively.

Example:

For instance, when calling a function as “test()” versus “await test()”, the former will execute and proceed with subsequent statements even during blocking operations, while the latter will wait for those operations to complete before moving on.

In this scenario, none of the async functions return promises by default, causing issues upon completion of their execution.

Detailed explanation specific to this example:

The initial call to “middleware()” triggers the chain of functions starting with “addColor()”.

addColor():
If the promise resolved from this function, it proceeds to call “getColor()”. Otherwise, it displays an error message.

Within addColor, we invoke validateColor() which performs the following check:

validateColor():
Upon resolving its promise, the color is added to the array; otherwise, an error is thrown.

Since validateColor encounters an error due to a null color, addColor erroneously assumes successful completion of its task.

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

Issue encountered while retrieving information using Axios in a Vue.js application

Currently, I am in the process of developing a full stack application using Vue.js and Fastify.js (a Node framework). The Vue app is supposed to retrieve data from the API I created and display it in the browser console. However, I am encountering an issue ...

Several treeviews for selecting data

I need some help with a specific assignment. The back end code is all set, but I'm struggling with the UI component. The task requires two tree views, one on the left and one on the right. The left tree view will contain states with multiple children, ...

AngularJS: iterating through POST requests and passing each index into its corresponding response

Using AngularJS, I am attempting to execute multiple http POST requests and create an object of successfully finished requests. Here is a sample code snippet: var params = [1, 2, 3], url, i, done = {}; for (i in params) { url = '/dir ...

What is the best way to insert an anchor tag into text using React?

I am working with a variable const linkElement = `Hey this is a link ${<a href="www.google.com">Click me!</a>} that can be clicked}` Currently, it displays as Hey this is a link [Object object] that can be clicked. Is there a way to ...

How to download a file using AJAX in Laravel?

Is there a way to download a CSV file within an ajax call? I have an ajax request in my Laravel controller that successfully retrieves the file contents in the response. However, I am facing issues with actually downloading the file. Laravel controller c ...

What is the process for making the default text in a text box appear grayed out?

Hey there! I have this cool idea for a text box. Basically, it starts off with default text but when you hover your mouse over it, the text disappears and you can start typing as usual: If you want to see how it looks like, you can check out this link: N ...

What steps can be taken to avoid an abundance of JS event handlers in React?

Issue A problem arises when an application needs to determine the inner size of the window. The recommended React pattern involves registering an event listener using a one-time effect hook. Despite appearing to add the event listener only once, multiple ...

Set the class of an element dynamically using ng-class and detect changes with ng-change

I want the input field to initially have the class .form-control-error. When the user clicks on the field and starts typing, I would like it to change to .form-control-success. I attempted the following code but couldn't get it to update. The ng-chan ...

Having trouble with Simplemodal showing link content in the modal window

Having trouble getting the modal window to display content from another link? I'm pretty sure I've connected them correctly using the right classes. This is the basic JavaScript provided by . jQuery(function ($) { // Load dialog on page load //$ ...

PHP-based user interface queue system

I am in the process of developing a website that enables users to manipulate a webcam by moving it from left to right. Each user will have a one-minute window to control the camera. I plan on implementing a queuing system on the site to ensure that users ...

Issue with Alignment of Border in PDF [Example Included]

I am currently developing a straightforward react application with very minimal content. index.js: <div className="App"> <div id="printable-div"> <h1>Generate PDF</h1> <p>Capture a screenshot of ...

The React server-side rendering isn't reflecting changes made on the client-side route

Upon the first refresh, both the server and client side are updated; however, subsequent updates only affect the client side when switching pages with react router. For instance, refreshing the page or entering a new URL causes changes on the server and t ...

Pairing items in a list using the concept of functional programming

Looking to arrange an array by grouping items together? For example: [1, 1, 0, 1, 0, 1, 0] => [1, 1, 0, 1, 1, 0, 0] OR [1, 1, 0, 1, 0, 1, 0] => [[1, 1], [0], [1, 1], [0, 0]] In this scenario, the goal is to group 1s with a maximum group size of 2 ...

Issue with manipulating currency conversion data

Currently, I am embarking on a project to develop a currency conversion application resembling the one found on Google's platform. The main hurdle I am facing lies in restructuring the data obtained from fixer.io to achieve a similar conversion method ...

Incorporate a dropdown menu based on the selection made in another dropdown menu

I have a scenario on my website where I want to dynamically add select boxes based on the value selected in the previous one. Here is the code snippet: <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.2.js"> </script> & ...

Tips for minimizing the padding/space between dynamically generated div elements using html and css

Currently, I have 4 dropdown menus where I can choose various options related to health procedures: Area, specialty, group, and subgroup. Whenever I select a subgroup, it dynamically displays the procedures on the page. However, the issue I am facing is th ...

What is the reason for hasChildNodes returning true when dealing with an Empty Node?

When the user clicks on purchase and the cart is empty, there should be an alert. However, it seems that no response is triggered. Upon running the program, an error message appears stating that it cannot read the property of addEventListener which is unde ...

Does the unique identifier of the element remain constant in jQuery?

For example: $("#savenew").live('click', function(e) { var user=<?php echo $user?>; $.ajax({ type: "POST", url: "actions/sub.php", data:{user: user} , ...

What is the best way to render components with unique keys?

I am currently working on a dashboard and would like to incorporate the functionalities of React-Grid-Layout from this link. However, I am facing an issue where the components are only rendered if they have been favorited. In order to utilize the grid layo ...

Tips for incorporating css @keyframes within a cshtml file:

My cshtml page includes a Popup that I created, but I encountered an issue with keyframes. When I tried to use it without keyframes, the fade effect was lost. I am looking for a way to fix my @keyframes. (I tested the code on Chrome and Opera) I found the ...