Handling errors and debugging (Part 1)

  • Last updated on 6th Aug 2022

Introduction

In this two-part post, I’ll be talking about how the JavaScript interpreter handles errors. I’ll be discussing how errors are thrown and how they can be caught and handled. I’ll also be talking about some of the best practices for error handling in JavaScript and some guidelines.

How the Interpreter processes and displays errors

The JavaScript interpreter will try to find the closest catch block to where the error occurred. If it finds one, it will execute the code inside that block. If it doesn’t find one, it will continue to look up the call stack until it either finds a catch block or reaches the global context / scope.

Error Object properties

When an error object is created, it contains the following properties. Some of the properties have varying support for browsers.

error-properties

Built-in Error Objects

Built-in error objects once hoisting is setup.

error-objects

I won’t be covering examples of the errors thrown in the browser console. With the post, I’d like to dive into the methodology I generally adapt and look for when something goes wrong.

Methodology

Debugging is about deduction and understanding. It’s a process of figuring out what’s wrong by working through the code line by line and understanding how it works. I’ll discuss the different approaches to debugging and my general steps. This is JavaScript specific, but I might do a css one as well in the future.

Debugging approaches

There are a few different approaches to debugging, but the most common is to use a debugger tool to step through the code line by line. This allows you to see the current state of the code and where the error is occurring. There are a few different debugger tools available, but the most popular ones are the browser debugger tools.

Personally, I use chrome dev tools and a couple of Visual Studio extensions. For the most part, they work really well (when you’re working with HTML, CSS, and JS) and even when you’re working with a framework like React you can view the “component stack” through the React Dev extension.

Identifying where the problem is

In longer scripts, looking at the error message tells you a couple of things. (1) The relevant script that pertains to the error. (2) The line number where the interpreter had a problem. Could also be earlier in the script, but in that (specific stack) is where the error object returned. (3) The type of error (this could be useless in some cases, and domain-specific, I’d say more-so with frameworks and niche npm modules).

Placing a console log message to output the state of a certain property. This is useful for form handling for some text input. Standalone snippet below:

console.log("getting pizza time value");

document.getElementById('pizzaTimeInput').addEventListener('blur', function(e) {
  console.warn('pizzaIs' + e.target.value);
  // conditionals here
}

Another approach is to communicate with others about the problem and talk it through. Or if it’s a solo thing—

error-objects

Finding the problem

(1) You could also have some set breakpoints within your script to pause the interpreter in that line. This way you can check if the values of the variables are what you expect them to be. If that isn’t the case you can look earlier in the script. Chrome Dev Tools has a feature that allows you to set breakpoints in the script, then check them. This is a great way to find the problem.

// to set a breakpoint in the script, then it'll show in dev tools
debugger

(2) You could also test for smaller functionality using smaller pieces or break down the code. You could do this by checking the console for a value using a switch statement. Since the console is an object with it’s own properties and methods, we can use console.warn. Like this:

switch (e.target.value) {
  case 'pizza':
    console.warn('pizzaIs' + e.target.value)
    break
  case 'burger':
    console.warn('burgerIs' + e.target.value)
    break
  case 'salad':
    console.warn('saladIs' + e.target.value)
    break
  default:
    console.warn('no value')
    break
}

Simultanously, we check if the value is what we expect it to be. We can also extend this and check for specific properties if we have a custom object. Let’s say we want to check if the value for an input matches one of our object properties.

const pizza = {
  name: 'pizza',
  price: '$10',
  description: 'a slice of pizza'
}

const burger = {
  name: 'burger',
  price: '$5',
  description: 'a burger'
}

document.getElementById('pizzaTimeInput').addEventListener('blur', function(e) {
  switch (e.target.value) {
    case pizza.name:
      console.warn(e.target.value === pizza.name ? 'is expected' : 'not expected');
      break;
    case burger.name:
      console.warn(e.target.value === burger.name ? 'is expected' : 'not expected');
      break;
    default:
      console.warn('no value');
      break;
  }
}

We can also check the number of parameters for a function, or the number of items in an array. Below we’re checking for the number of items in the getMenuItem.

const pizza = {
  name: 'pizza',
  price: '$10',
  description: 'a slice of pizza',
}

const burger = {
  name: 'burger',
  price: '$5',
  description: 'a burger',
}

const salad = {
  name: 'salad',
  price: '$5',
  description: 'a salad',
}

const menu = [pizza, burger, salad]

function getMenuItem(item) {
  if (item.length === 3) {
    console.log('we have a menu item with: ' + item.length + ' items')
  } else {
    console.log('we do not have a menu item')
  }
}

getMenuItem(menu)

Your also able to write a group message to the console with the group and groupEnd method.

// previous example here

console.group('menu')
console.log('we have a menu item with: ' + menu.length + ' items')
console.groupEnd('menu')

Ending Thoughts

In this first part, I’ve covered some practical workflows for debugging JavaScript. The JavaScript debugger can help you step through your code line by line, set breakpoints, and inspect variables. Using a debugger can help you find and fix errors in your code more quickly and efficiently. In part two, I’ll talk about exception handling.