JavaScript Best Practices

JavaScript Clean Code: Error Handling

Spread the love

Error handling is an important part of programs. There are many situations where our programs encounter values that are unexpected and we have to properly handle them.

In this article, we’ll look at how to handle them so that errors are easily found easily and gracefully handled.

Exceptions are Better than Return Codes

Throwing exceptions is better because they let us know that an error exists and that we have to handle it.

Most modern programming languages have exceptions built-in, so we should throw them instead of returning an error code.

Error codes aren’t as explicit and may be missed. Exceptions are also much cleaner since we don’t have to check all the codes that may be returned.

For example, if we return error codes in our functions then we may have code that looks something like this:

We have to return all the error codes in our setNumFruit method. Also, before we do something after the class definition, we have to check all the error codes.

We can throw exceptions instead:

We’ve eliminated the need to check all the error codes by wrapping the code we want to run in a try block. Now we can just catch the error instead of checking all the error codes that may be returned.

This is much better than checking all error codes before doing something — it’s especially important as code becomes more complex.

Write Try-Catch-Finally

We should wrap our try in the code that throws exceptions that we want to catch. It creates its own scope for block-scoped variables so anything declared with let or const can only be referenced in the try block.

Variables declared with var are hoisted so that they can be referenced outside the block. We won’t get an error even if they’re referenced outside the block. This will get us 1:

try {  
  var x = 1;  
} catch (ex) {  

But this will get us Uncaught ReferenceError: x is not defined:

try {  
  let x = 1;  
} catch (ex) {  

Don’t Ignore Caught Errors

We should report our errors when they’re caught. They shouldn’t be caught and then ignored. This is because we don’t want to sweep underlying issues under the rug.

Reporting exceptions let us know about the error and then handle it accordingly.

The examples above, like the console.error, call in the following:

try {  
  const error = fruitStand.setNumFruit(1);  
} catch (ex) {  

Thi s one of the ways to report the error. We can also use other libraries to report the error in a central place.

Don’t Ignore Rejected Promises

Like any other exception, rejected promises also need to be handled. They can be handled with the callback that we pass into the catch method or use the try...catch block for async functions — they’re the same.

For example, we can report the error by writing the following:

  .catch(err => {  

Or for async functions we can write this:

(async () => {  
  try {  
    await Promise.reject('fail')  
  } catch (err) {  

Providing Context with Exceptions

We should provide enough context in exceptions that other developers can pinpoint the error when an exception is thrown.

We can get a stack trace with exceptions in JavaScript, but it may not provide all the information we need.


When we handle errors, throwing exceptions is better than returning error codes since they let us use the try...catch block to handle errors. This is much cleaner than checking multiple error codes.

When we throw exceptions, we have to provide enough details to pinpoint the problem.

We shouldn’t just ignore errors after catching them. We should at least report them so that they can be looked at.

Finally, rejected promise errors should be handled the same way as other exceptions.

By John Au-Yeung

Web developer specializing in React, Vue, and front end development.

Leave a Reply

Your email address will not be published. Required fields are marked *