In JavaScript, errors are only detected during runtime. Therefore, it is impossible to get compile-time errors when building JavaScript applications.

There are several reasons an app might encounter a JavaScript exception: invalid input, server error, syntax errors, or errors in the application logic.

In this article, we will dig into exception handling in JavaScript so that when your app encounters errors, it affects users as little as possible. Exception handling allows us to write custom behavior for different errors caused by application users, the server, and many other causes of these errors.

What is exception handling?

Applications occasionally run into problems like syntax errors. Operations such as dividing a non-zero number by zero, calling a method with incorrect arguments, or failing to read a file could give a JavaScript exception in our code.

JavaScript exception handling is the procedure/method used to handle the abnormal behavior of our JavaScript applications. It is the method used to handle the possibility of failure in applications as gracefully as possible.

With proper exception handling and good logging, we can handle abnormal conditions or crashes and help the user take necessary actions with a proper exception handling error messages.

Why is exception handling in JavaScript important?

When application code generates errors and raises exceptions, it often doesn’t make sense to continue with the remaining code. Instead, applications should try to recover from the error by using exception handling.

Without properly handling JS exceptions, they may crash the application and frustrate a user. Noticing and handling errors or possible failures of an application, often called "catching the exception", saves programs from cascading the failure up the call stack.

If an unexpected response is given method and then processed by the caller, the user gets incorrect information and a bad impression of the application. A well-written application should have a good exception handling mechanism and approach to various kinds of errors that are likely to happen within the application during usage.

With exception handling, we can manage these problems and prevent the application from crashing. By using exception handling, we can control the flow of an application.

How to handle exceptions in JavaScript

There are many ways to handle exceptions in JavaScript. JavaScript provides a mechanism to handle errors using the try-catch-finally block, similar to languages like Java and C#.

The mechanism can be used in a few different ways:

  • throw statements
  • try-catch
  • try-catch-finally

Try blocks

Executable code that you know may raise exceptions or cause errors should be placed in a try block.

When an exception is thrown in the try block, it passes the error to the catch block, and the necessary actions can be taken in the catch block. If the necessary actions are not taken by the catch block, the application may behave abnormally, and a crash is likely to occur.

Catch blocks

The code that should be executed when JavaScript exceptions happen in the try block is written in the catch block. The exception handling code is usually written in the catch block.

The catch block can contain either the user-defined exception handler or the built-in error handler in JavaScript.

Note that the catch block only executes when there is an error from the try block. There can also be more than one catch block to handle multiple exceptions.

Finally blocks

The finally block will execute regardless of whether there is a syntax error from the try block.

Try-catch statements

Try-catch statements are not only common in JavaScript but also widely used in other programming languages. They are used to handle exceptions that arise in the code.

JavaScript uses try-catch statements to trap runtime errors and handle them properly.

Try blocks contain code that might throw runtime errors, and a catch statement contains code to handle the exception if an error occurred. When a try block encounters errors, the catch block is triggered. Otherwise, execution continues after each try-catch statement. Here is an example:

try {
  thisfunctiondoesnotexit()
}

catch(e) {
  console.log(e);
}

In the code above, we attempt to use a function that does not exist in the application. The try block throws an error to the catch block, which logs it to the console.

JavaScript try-catch-finally statements

A try-catch statement can also be written with an added finally block. The code in the finally block executes, regardless of whether an error occurs in the try statement.

The following is an example of how you can use try-catch-finally to handle errors in JavaScript:

try {
  thisfunctiondoesnotexit();
}
catch(e) {
  console.log(e);
}
finally {
  console.log("Code executed successfully");
}

In this example, the finally block will run regardless of whether the try block throws an error.

Using throw statements allows for custom errors to be thrown into the catch block, which is handled based on the code in the catch block.

Let's take a look at some more complicated JavaScript error handling examples. We will create a simple calculator that accepts user input in JavaScript and make use of exception handling and promises to generate custom error messages.

Run the JavaScript code below in your browser, and we'll walk through how it works.

const throwExceptions = () => {
  let result
  let first = prompt('Enter first number: ')
  let second = prompt('Enter second number: ')
  try {
    if (first == '' || second == '') throw 'Number cannot be empty'
      result = first / second
    } catch (err) {
        console.log(err)
    } finally {
        console.log(`The division of ${first} & ${second} is ${result}`)
    }
}
throwExceptions()

Here, we have created a function that handles exceptions it might encounter.

In this example, we prompt the user to input two numbers. These two numbers will then be divided by each other, with the first number being the numerator and the second being the denominator.

Then we use the JavaScript if and throw statement to test whether the input given by the user is valid (i.e., whether it is empty).

In our code, we throw a custom error using the throw statement. We can also do some other checks on the user input to check for validity and send the JavaScript errors to the catch block if there are any. The catch block catches errors and displays the message defined in throw statements.

This allows for control and better flow handling of the application by the developer and also helps the user to know what went wrong and why the application does not give the expected result.

The finally block executes regardless of whether an error is thrown and is used to display the result of the operation, even when there is an error.

In addition to errors defined by the throw statement, other errors can also be caught and displayed in the catch block. The throw statement only allows for flexibility and custom error definition.

Using the try-catch-finally statement in JavaScript is a good example of how to handle exceptions and errors. However, there is more.

Handling errors with JavaScript promises

We can also catch errors using JavaScript promises. We will build the same program using JavaScript promises. Run the JavaScript code below in your browser, and let's take a closer look.

const throwExceptions = (first, second) => {
  return promise = new Promise((resolve, reject) => {
  if (first == '' || second == '') reject ('Number cannot be empty')
      resolve(first / second)
  })
}

let first = prompt('Enter first number: ')
let second = prompt('Enter second number: ')

throwExceptions(first, second)
  .then(result => console.log(result))

The code above helps us handle our simple calculator script using JavaScript promises. While the implementation differs, the functionality of this example is the same as the previous one. Only the implementation differs. We have only used promises to more effectively handle our errors.

Promises are a great way to handle errors in asynchronous code. They provide better ways to handle asynchronous operations than callbacks and events.

We created and returned a new promise object in our function: throwExceptions. Our new promise tests for the input and rejects it if it is invalid. The operation will be processed, and the result will be displayed if the input is valid.

We can do more checking and get more detailed information about errors when they occur with Honeybadger, an application monitoring tool.

How to handle exceptions with Honeybadger

Honeybadger provides developers with a tools to better understand and fix errors. With Honeybadger, developers and businesses can track and manage application errors, keeping users happy.

Let's walk through the steps you need to get started with Honeybadger and how to monitor errors in your application with Honeybadger.

In this application, we will try to access a function that does not exist. This will raise an error. We will then use Honeybadger to monitor and get more detailed information about this error.

Step 1 - Create a Node project

Start by creating a Node project. Create a folder and give it a meaningful name.

mkdir test-app && cd test-app && npm init

Then, install Express:

npm install express

Step 2 - Write a simple hello world app

Create an index.js file in the root of the application and put in the following code:

const express = require('express')
const app = express()
const port = 3000

app.get('/', (req, res) => {
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

Step 3 - Sign up for Honeybadger

Sign up for a Honeybadger Free trial.

The Honeybadger homepage The Honeybadger homepage

Step 4 - Create a new Honeybadger project

Click on ‘add project’ and give your project a name. Next, select Node.js, and you'll see instructions for installing Honeybadger:

Exception handling in JavaScript with a new Honeybadger project Creating a new Honeybadger project

Step 5 - Install and configure Honeybadger

First, install Honeybadger as an NPM dependency:

npm add @honeybadger-io/js --save

Finally, we can configure Honeybadger with the API key we were given when creating the new project, then throw and catch an exception to demonstrate reporting to Honeybadger. Update index.js to this:

const express = require('express')
const app = express()
const port = 3000

// Configure honeybadger
const Honeybadger = require("@honeybadger-io/js");
Honeybadger.configure({
  apiKey: "hbp_1bVSXwW2zJwZio8NV6IDeCNpSbY1yk3889mg",
  environment: "production"
});

app.get('/', (req, res) => {
    try {
      thisfunctiondoesnotexit()
    } catch(e) {
      Honeybadger.notify(e);
    }
  res.send('Hello World!')
})

app.listen(port, () => {
  console.log(`Example app listening on port ${port}`)
})

In the program above, we try to access a function that does not exist. This code produces an error when it runs. Let’s take a look at how Honeybadger helps us manage this error from our Honeybadger account.

Run the project locally with:

node index.js

Then, trigger the code by visiting localhost:3000 in your browser.

Navigate to your Honeybadger account and open up the project we created earlier. Click on the error tab and see which error is displayed. To get more information about this error, click on the error. This will display more detailed information about the error in your code, as shown in the following image:

Honeybadger error page showing the caught exception The Honeybadger error page

If you have successfully configured your application with Honeybadger, you should get a screen that looks like this. This screen shows the ReferenceError in your code.

This page displays all relevant information about the error in your code, such as the error message, at what line the error occurred, and other relevant details. Honeybadger is a great tool for developers who are willing to satisfy their customers and minimize errors and bugs in their applications.

Try out the simple calculator we have built in this article and see how Honeybadger helps you track these errors conveniently.

Building reliable JavaScript applications

In JavaScript development, errors are bound to happen. Errors in application code can be tedious to find and can be expensive when they occur and crash applications. With techniques for exception handling in JavaScript and even monitoring tools like Honeybadger, you can ship with confidence.

Effective error handling isn't just about preventing crashes, but building a better user experience and ultimately shipping more reliable applications. As you continue your JavaScript journey, make exception handling an integral part of your coding practice.

Try Honeybadger for FREE

Honeybadger helps you find and fix errors before your users can even report them. Get set up in minutes and check monitoring off your to-do list.
Start free trial
Easy 5-minute setup — No credit card required
author photo
Salem Olorundare

Salem is a software engineer who specializes in JavaScript. He enjoys breaking down advanced technical topics in his writing so they can be understood by people of all skill levels.

More articles by Salem Olorundare