Why Your JavaScript Code Needs Error Handling

Jawara Gordon
7 min readApr 16, 2023

--

What is Error Handling?

Error handling is an important part of software development.

It involves preparing for unexpected situations that can happen with any software application. When errors occur, they cause the program to malfunction or possibly crash, leading to poor user experience and more serious issues like data loss.

It’s crucial to have proper error handling that can deal with problems gracefully while notifying the user and offering feedback to developers.

Effective error handling improves the reliability, performance, and usability of your applications, making it an essential step in your development process.

Different Types of Errors

There’s an endless list of errors you’ll run into while building an application. Here are some of the most common:

  • Syntax errors: When your code violates the rules of the programming language. Missing closing brackets, semicolons, or indentations are the usual suspects.
  • Runtime errors: When your code tries to execute an invalid operation or access an undefined variable or object.
  • Logical errors: When your code produces incorrect results due to bad logic or algorithms. Using the wrong conditional statement or type of loop will lead to these errors.
  • Network errors: When the application can’t connect to a server or fetch data from an API. This could result from network latency, timeouts, or non-responsive servers.
  • Security errors: When your application is vulnerable to attacks like cross-site scripting (XSS), SQL injection, or authentication bypass, allowing unauthorized access or manipulation of data.

Learning to manage these errors is an important part of your growth as a software developer. Remember — these “little red friends” are here to help you find the answers so make sure you listen to them carefully without taking things too personally.

JavaScript Error Handling Methods

Developers have access to many types of error-handling features that can be used to manage issues in their code.

One of the most common tools is try-catch blocks, which catch errors in a specific block of code.

Another approach is using callback functions to handle errors that occur during async/await operations.

There are also third-party error-handling libraries like Sentry and Rollbar, that can be used inside JavaScript applications to provide more advanced features.

Choosing the best approach depends on the specific needs of your application.

So Many Errors!

I’ve recently graduated to building more complicated apps which has led to more complex logic, and as a result, more errors.

Handling errors in your code can feel overwhelming when you’re following stack traces and sifting through thousands of lines of code.

Using effective error messages is a great way to reduce downtime and increase productivity. But what happens when you find yourself repeating the same try-catch blocks over and over again? That’s far from DRY code.

Centralized Error Handling

Centralized error handling is the practice of handling errors that occur throughout an application in a single location.

Instead of managing errors at multiple points in the code, centralized error handling ensures that errors are handled in a uniform way. This approach makes it easier to identify and debug errors.

Utilizing this method will improve performance, create consistency and allow developers to customize messages based on the specific needs of an application.

Error Handling Functions

All of this sounds great on paper, but how do you integrate centralized error handling into your apps?

Create error handling functions.

These specialized functions live inside their own JavaScript file and wrap all of your error handling in a centralized and organized manner.

Let’s take a closer look with a code example:

Create a new file called ‘app.js’:

$touch app.js

Define a function called ‘divideNumbers’ that takes two parameters: ‘numerator’ and ‘denominator’.

function divideNumbers(numerator, denominator) {
return numerator / denominator;
}

Test it out in your console:

This is going great so far! But… what if the user tries to use arguments that aren’t numbers?

The only feedback we’re getting is NaN which is not great for debugging or letting the user know what went wrong.

Let’s add some simple logic to make sure the user enters the correct type of data:

function divideNumbers(numerator, denominator) {

if (typeof numerator !== 'number' || typeof denominator !== 'number') {
throw new TypeError('Numerator and denominator must be numbers');
}
return numerator / denominator;
}

Hello, little red friend 👋🏽

This is much better. We now know that we created a TypeError by using strings instead of numbers.

Next, let’s handle a new bug that QA found in our app. Users should not be able to enter zero as a denominator:

Add the following error message to your function:

function divideNumbers(numerator, denominator) {
if (typeof numerator !== 'number' || typeof denominator !== 'number') {
throw new TypeError('Numerator and denominator must be numbers');
}
if (denominator === 0) {
throw new RangeError('Denominator cannot be zero');
}
return numerator / denominator;
}

Great! Now we can display a helpful message explaining what went wrong:

Another round of QA has discovered a new bug. This app is being used to manage inventory that only works with integers but this function allows users to input decimals.

Adding this conditional logic will fix that problem:

function divideNumbers(numerator, denominator) {
if (typeof numerator !== 'number' || typeof denominator !== 'number') {
throw new TypeError('Numerator and denominator must be numbers');
}
if (denominator === 0) {
throw new RangeError('Denominator cannot be zero');
}
if (!Number.isInteger(numerator) || !Number.isInteger(denominator)) {
throw new Error('You must use a whole number');
}
return numerator / denominator;
}

Now we have an easy-to-understand message letting the user know what went wrong:

Good work! This app is handling all of the errors while creating easy-to-track messages. This method works well with a small program, but will quickly get lost when we add functions to manage multiplication, and other needs as our app grows.

A Better Way

Instead of duplicating all of this error handling into our next function, we can utilize centralized error handling to create DRY code.

Create a new file called ‘errorHandlers.js’:

$touch errorHandlers.js

Add this code to handle all of your errors in a centralized location:

function handleError(err) {
if (err instanceof TypeError) {
console.error(`TypeError: ${err.message}`);
} else if (err instanceof RangeError) {
console.error(`RangeError: ${err.message}`);
} else {
console.error(`Error: ${err.message}`);
}
}

We’re checking the type of error that occurred using instanceof.

If it’s a TypeError, we’re logging the message with ‘TypeError’. If it’s a RangeError, we’re logging the message with ‘RangeError’. Otherwise, we’re simply logging the message with ‘Error’.

You can modify these messages to fit your specific error-handling needs.

The final step is to put our new handleError function to work.

Wrap your ‘app.js’ ‘divideNumbers’ function in a single try-catch block while capturing the return into a variable called ‘result’ and passing handleError(err) into the catch block:

try {
const result = divideNumbers(100,25);
console.log(`Result: ${result}`);
} catch (err) {
handleError(err);
}

This yields the correct result in an easy-to-read format when called with arguments that follow the rules defined in our function:

Try it yourself with this live demo:

Summary

Error handling is an important part of software development that helps to manage expectations while allowing for more efficient debugging.

Creating a centralized location to handle errors is an excellent way to improve performance while creating more readable and DRY code. Using an error-handling function instead of try-catch blocks in individual functions will not only provide more customized feedback but will also create easier-to-test applications.

You can save yourself and your team valuable time by implementing the solutions outlined in this article. Try experimenting with different error-handling techniques and see how they can help you build more user-friendly code.

With a little effort and practice, you’ll be able to write programs that not only work but also work well!

Sources

https://github.com/martinmurciego/good-books/blob/master/Clean%20Code_%20A%20Handbook%20of%20Agile%20Software%20Craftsmanship%20-%20Robert%20C.%20Martin.pdf

https://en.wikipedia.org/wiki/Wikipedia:Reporting_JavaScript_errors

Resources

https://github.com/JawaraGordon/errorHandling-demo

https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Control_flow_and_error_handling

https://www.w3schools.com/js/js_errors.asp

https://docs.rollbar.com/docs/javascript

--

--

Jawara Gordon

Jawara (jah-WAH-rah): Full-Stack Web Developer | Audio Engineer JavaScript, React, HTML, CSS/SASS, Ruby on Rails | Ableton Live