DEV Community

Cover image for Build a Javascript async function error handler
Nathaniel
Nathaniel

Posted on

Build a Javascript async function error handler

Background

If you are a Js developer, you probably have used async and await, and you love them.

No more callback hell or .then chains. Just like writing a synchronous program.

Util you run into UnhandledPromiseRejectionWarning or Uncaught (in promise) Error

You begin to wrap every piece of code using try.. catch.., but that seems a lot of work.

But I've got good news, you can write a custom async function error handler:

Solution

const asyncHandler = fn => async (...args) => {
  try {
    await fn(...args);
  } catch (err) {
    console.log(err);
  }
};
Enter fullscreen mode Exit fullscreen mode

It takes all types of functions with any number of arguments.

use it like this:

const asyncHandler = fn => async (...args) => {
  try {
    await fn(...args);
  } catch (err) {
    console.log(err);
  }
};

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const yourFunction = async () => {
  await sleep(2000);
  throw 'something wrong';
  return 'success';
}

(async ()=> {
  await yourFunction(); // will cause Uncaught error
  await asyncHandler(yourFunction)(); // will handle the error properly
})();
Enter fullscreen mode Exit fullscreen mode

Return values

Of course when you need the result of the async function, you can:

const asyncHandler = fn => async (...args) => {
  try {
    return await fn(...args);
  } catch (err) {
    console.log(err);
  }
};

function sleep(ms) {
  return new Promise(resolve => setTimeout(resolve, ms));
}

const yourFunction = async () => {
  await sleep(2000);
  // throw 'something wrong';
  return 'success';
}

(async ()=> {
  const result = await asyncHandler(yourFunction)(); //will handle the error properly
  console.log(result); // => 'success'
})();
Enter fullscreen mode Exit fullscreen mode

Custom error handling

if you need some custom error handling, for example, to use it in express.js

you can do simply by adding some of your custom logic

const asyncHandler = fn => async (...args) => {
  try {
    await fn(...args);
  } catch (err) {
    logger.error(err);
    const resFn = args.find(arg => arg.name === 'res');
    if (resFn) {
      let errors = {
        message: 'Internal Sever Error',
        error: err
      };

      if (err instanceof mongoose.Error.ValidationError) {
        errors = {
          message: 'Mongoose Model Validation Error',
          error: err
        };
      }
      if (err instanceof mongoose.mongo.MongoError) {
        errors = {
          message: 'MongDB Error',
          error: err
        };
      }

      resFn.status(500).json(errors);
    }
  }
};
Enter fullscreen mode Exit fullscreen mode

later you use it in express routers like this:

router.get('/item',
  asyncHandler(async (req, res) => {
    // router logic here
  })
)
Enter fullscreen mode Exit fullscreen mode

Discussion (2)

Collapse
josephakayesi profile image
JosephAkayesi • Edited

Can I pass a custom error object to the asyncHandler from with the '/item' route

Collapse
llldar profile image
Nathaniel Author

Sure, you can throw custom error, and handle it in asyncHandler, just make sure you have a way to identify it.