Simplifying Async Error Handling in JavaScript with await-of

In this latest blog from the developers on our Product Traction team, they outline their expertise simplifying Async error handling in JavaScript with `await-of`.

When working with asynchronous code in JavaScript and TypeScript, one of the most common patterns involves using `async/await` along with `try/catch` blocks for handling errors. While this pattern is widely adopted, it can clutter your code with repetitive try/catch logic. Enter the `await-of` package, a handy utility that simplifies this pattern by enabling you to destructure the result and error from an asynchronous function directly.

In this post, we’ll dive into the `await-of` package, explore its benefits, and touch on some potential drawbacks. We’ll also provide code examples to demonstrate its usage and explain why this tool might be a good fit for your project—or not.

What is `await-of`?

`await-of` is a small utility package designed to simplify async error handling in JavaScript and TypeScript. Instead of using the traditional `try/catch` block, `await-of` lets you handle the result and the error in a single destructured array. This can help tidy up your code by reducing the need for wrapping every asynchronous call in a `try/catch` block.

Installation

You can easily add the `await-of` package to your project by running:

npm install await-of

Benefits of `await-of`

1. Tidier Code

One of the key advantages of `await-of` is that it tidies up your code by eliminating the repetitive `try/catch` pattern. Let’s compare a traditional `try/catch` block with an example using `await-of`.

Without `await-of`:

async function getUser(id) {

    try {

        const user = await fetchUser(id);

        return user;

    } catch (error) {

        console.error('Failed to fetch user:', error);

        return null;

    }

}

With `await-of`:

import { of } from 'await-of';

async function getUser(id) {

    const [user, error] = await of(fetchUser(id));

    if (error) {

        console.error('Failed to fetch user:', error);

        return null;

    }

    return user;

}

By using `await-of`, you can avoid the nested `try/catch` block, making your code cleaner and easier to follow.

2. Destructuring Results

`await-of` allows you to destructure the result and error into `const` variables directly, making it clear what you are handling. This pattern allows you to define your variables inline, avoiding the need to define them before the `try/catch` block.

Here’s a more complex example:

async function processData(userId) {

    const [user, userError] = await of(fetchUser(userId));

    const [posts, postsError] = await of(fetchUserPosts(userId));

    if (userError) {

        console.error('Error fetching user:', userError);

        return;

    }

    if (postsError) {

        console.error('Error fetching posts:', postsError);

        return;

    }

    return { user, posts };

}

Notice how each asynchronous call is handled in a consistent and clean way using destructuring.

Potential Drawbacks of `await-of`

While `await-of` brings significant improvements to async code readability, it’s not without its downsides.

1. Requires a Shift in Error Handling Mindset

Using `await-of` changes the way you think about error handling. Instead of catching errors in a `catch` block, you’re explicitly checking whether an error has occurred by examining the second value in the destructured array. This shift may require some adjustment, especially if you’re used to the more traditional `try/catch` approach.

Here’s a side-by-side comparison:

Traditional `try/catch`:

try {

    const data = await someAsyncFunction();

    // Do something with data

} catch (error) {

    console.error('An error occurred:', error);

}

With `await-of`:

const [data, error] = await of(someAsyncFunction());

if (error) {

    console.error('An error occurred:', error);

}

While this might seem like a minor difference, the need to explicitly handle the error could lead to missing errors if you forget to check the second value. This introduces a different form of discipline when writing async code.

2. Unfamiliarity for New Team Members

In TypeScript, destructuring arrays is a common pattern. However, returning multiple values from a function inside an array (which is what `await-of` effectively does) may not be immediately intuitive for some developers. This pattern can be confusing, particularly for those who are new to JavaScript or TypeScript or those unfamiliar with how `await-of` works.

For example, in the following snippet, someone unfamiliar with this pattern might be unclear about why an array is being returned:

const [data, error] = await of(someAsyncFunction());

If this pattern is used extensively throughout a codebase, it may require some onboarding or documentation to ensure new developers understand what’s happening.

The `await-of` package is a useful tool for simplifying asynchronous code in JavaScript and TypeScript, offering a cleaner, more streamlined alternative to traditional `try/catch` blocks. By using destructuring, it lets you handle results and errors more concisely. However, it’s important to consider the shift in error-handling philosophy and potential confusion for new developers before adopting it widely in your codebase.

If your goal is to improve code clarity and reduce boilerplate, `await-of` can be a great addition. However, if your team values familiarity and explicit error handling, you might want to weigh the trade-offs before diving in.

For those who want to give it a shot, try installing `await-of` in your next project and see how it works for you!

Happy coding!


Further Reading:

The Thin Air Labs Product Traction team provides strategic product, design and development services for companies of all sizes, with a specific focus on team extensions where they seamlessly integrate into an existing team. Whether they are deployed as a team extension or as an independent unit, they always work with a Founder-First Mindset to ensure their clients receive the support they need.

To learn more about our Product Traction service, go here.

Build what's next with us