JavaScript: Using AggregateError to Handle Exceptions

Updated: February 14, 2024 By: Guest Contributor Post a comment

Handling exceptions efficiently and effectively is crucial in any programming environment, and JavaScript is no exception. With the introduction of AggregateError, JavaScript developers have a more versatile way to handle multiple errors as a single entity. This tutorial will guide you through the basics of AggregateError, followed by progressively more advanced use cases, complete with code examples and explanations.

Introduction to AggregateError

The AggregateError object is a JavaScript error type that represents multiple errors wrapped in a single object. This capability is particularly useful in scenarios where operations like Promises.all or Promises.allSettled are utilized, and multiple errors might be thrown. Before the introduction of AggregateError, handling these multiple errors was cumbersome and inelegant. Now, developers can catch all errors in a single catch block and process them according to their needs.

Basic Example

Promise.all([
    Promise.reject(new Error('Error 1')),
    Promise.reject(new Error('Error 2'))
]).catch(e => {
    if (e instanceof AggregateError) {
        for (const individualError of e.errors) {
            console.log(individualError.message);
        }
    } else {
        console.log(e);
    }
});

This block demonstrates the use of AggregateError in a Promise.all scenario. Here, two promises are rejected, resulting in an AggregateError. The code checks if the error is an instance of AggregateError and then iterates over the individual errors to log their messages.

Handling Errors in Async Functions

Asynchronous functions can also benefit from AggregateError. By using async/await syntax combined with try/catch blocks, we can elegantly handle multiple errors.

async function loadData() {
    try {
        const results = await Promise.all([
            fetch('url_that_fails1'),
            fetch('url_that_fails2')
        ]);
        return results;
    } catch (e) {
        if (e instanceof AggregateError) {
            for (const error of e.errors) {
                console.error(error);
            }
        } else {
            console.error(e);
        }
    }
}

In this example, two network requests are made using fetch. Both requests fail, triggering the catch block where the error is checked to be an AggregateError. The code then iterates through each error, logging them.

Advanced Use Cases

With the basics covered, let’s explore more complex scenarios where AggregateError improves error handling.

Custom AggregateErrors

Sometimes, you might want to create an AggregateError manually, for example, when handling errors from different parts of your application. This gives you the flexibility to aggregate and throw errors as you see fit.

const error1 = new Error('Custom error 1');
const error2 = new Error('Custom error 2');

try {
    throw new AggregateError([error1, error2], 'Two custom errors occurred.');
} catch (e) {
    console.log(e.message); // 'Two custom errors occurred.'

    for (const error of e.errors) {
        console.log(error.message); // 'Custom error 1' and then 'Custom error 2'
    }
}

This example demonstrates creating a custom AggregateError. The AggregateError constructor takes an array of errors and an optional message. This allows for detailed error reporting and handling.

Integrating With Promise.any

Promise.any is a method that resolves if any of the included promises resolve but rejects with an AggregateError if all promises reject. This behavior makes it an excellent candidate for AggregateError handling.

Promise.any([
    Promise.reject(new Error('Fail 1')),
    Promise.reject(new Error('Fail 2'))
]).catch(e => {
    if (e instanceof AggregateError) {
        // Handling code here
    }
});

In this example, both promises within Promise.any reject, which results in an AggregateError. The catch block then processes this error, similar to our earlier examples.

Conclusion

The AggregateError object enhances JavaScript’s error handling capabilities, allowing developers to manage multiple errors in a clean and efficient manner. Whether you are working with asynchronous operations, integrating multiple sources, or dealing with complex logic, AggregateError can simplify your error handling strategy and make your code more readable and maintainable. The examples provided demonstrate the versatility and power of AggregateError in various scenarios, thus showcasing its utility in modern JavaScript development.