Error handling in Javascript - Catch errors in Javascript

Let's be fair, there's no way of programming without creating and running into errors. Of course, what makes the difference is how you handle said errors. And Javascript is no stranger to error to a not so awesome error handling system.

What are Javascript errors and how do you handle them

JavaScript errors are issues that will occur during the execution of JavaScript code. When the JavaScript interpreter encounters a mistake or an issue in your code, it generates an error message to notify you about what happened. These errors can be classified into a few diffrent types, based on their nature and cause. So here are some common JavaScript error types:

1. Syntax Errors

Syntax errors occur when the code violates the JavaScript language rules. It could be a missing parenthesis, a typo, or incorrect placement of semicolons. These errors prevent the code from being executed.

// Missing closing curly brace
function greet() {
  console.log("Hello, World!");
// Output: Uncaught SyntaxError: Unexpected end of input

2. Reference Errors

Reference errors occur when the code tries to access a variable or function that does not exist or is out of scope. It happens when you try to use a variable without declaring it or accessing properties of an undefined object.

// Using a variable outside its scope
function outer() {
  var message = "Hello";

  function inner() {
    console.log(message);
  }

  inner();
}

outer();
// Output: Hello

3. Type Errors

Type errors occur when an operation is performed on a value of an inappropriate type. For example, trying to call a non-function, accessing a property on a non-object, or performing arithmetic operations on incompatible data types.

// Accessing a property of an undefined object
var person = {
  name: "John",
  age: 25
};

console.log(person.address.city);
// Output: Uncaught TypeError: Cannot read property 'city' of undefined

4. Range Errors

Range errors occur when a value is not within an acceptable range or set of values. This can happen with operations like array indexing, where the index is outside the allowed range of values.

// Using recursion without a base case
function countdown(num) {
  if (num >= 0) {
    console.log(num);
    countdown(num - 1);
  }
}

countdown(10);
// Output: Uncaught RangeError: Maximum call stack size exceeded

5. DOM Errors

DOM (Document Object Model) errors occur when manipulating HTML elements and the DOM structure. These errors can happen when attempting to access or modify elements that do not exist or are not yet available in the DOM.

// Modifying a non-existent element's style
var element = document.getElementById("nonExistentElement");
element.style.color = "red";
// Output: Uncaught TypeError: Cannot set property 'color' of null

6. Network Errors

Network errors occur when JavaScript code interacts with network resources such as making HTTP requests. These errors can be caused by issues like server unavailability, network connectivity problems, or incorrect request configurations.

// Handling AJAX request error
var request = new XMLHttpRequest();
request.open('GET', 'https://api.example.com/data', true);
request.onerror = function() {
  console.log("An error occurred during the request.");
};
request.send();

7. Runtime Errors

Runtime errors occur during the execution of JavaScript code and can be caused by a variety of issues such as logical errors, unexpected data, or external factors. These errors often require careful debugging and troubleshooting to identify and fix the problem.

// Dividing a number by zero
function divide(a, b) {
  if (b !== 0) {
    return a / b;
  } else {
    throw new Error("Divide by zero error.");
  }
}

try {
  var result = divide(10, 0);
  console.log(result);
} catch (error) {
  console.log(error.message);
}
// Output: Divide by zero error.

Our best practices for error handling in Javascript

As you can imagine, error handling is the most important aspects of your work as a programmer and consequently, of working in Javascript. Below we'll outline a few of the best practices we've gathered for you:

1. Use try-catch blocks

Wrap the code that might throw an error in a try block and use catch blocks to handle specific types of errors. This allows you to gracefully handle errors and provide appropriate error messages or fallback behavior.

try {
  // Code that may throw an error
} catch (error) {
  // Handle the error
}

2. Be specific in error handling

Catch specific types of errors to handle them differently. This helps you identify and respond to different error scenarios appropriately. For example, you can catch specific errors like TypeError or ReferenceError to handle them differently than generic errors.

try {
  // Code that may throw an error
} catch (error) {
  if (error instanceof TypeError) {
    // Handle type error
  } else if (error instanceof ReferenceError) {
    // Handle reference error
  } else {
    // Handle other errors
  }
}

3. Provide descriptive error messages

When handling errors, include meaningful error messages that provide helpful information about the error. This makes it easier to identify the cause of the error and helps with troubleshooting.

try {
  // Code that may throw an error
} catch (error) {
  console.error("An error occurred:", error.message);
  // Handle the error
}

4. Use the finally block

The finally block allows you to specify code that should be executed regardless of whether an error occurred or not. It is useful for cleanup tasks or releasing resources.

try {
  // Code that may throw an error
} catch (error) {
  // Handle the error
} finally {
  // Code to be executed regardless of error occurrence
}

5. Handle asynchronous errors

When working with asynchronous operations like promises or async/await, make sure to handle errors appropriately. Use the catch method on promises or surround async/await blocks with try-catch for error handling.

// Using promises
somePromise()
  .then(result => {
    // Handle success
  })
  .catch(error => {
    // Handle error
  });

// Using async/await
async function someAsyncFunction() {
  try {
    const result = await somePromise();
    // Handle success
  } catch (error) {
    // Handle error
  }
}

6. Logging errors

Implement proper error logging to capture errors during runtime. Logging the errors, along with relevant details, can help in debugging and diagnosing issues. Use the console or dedicated logging libraries for this purpose.

try {
  // Code that may throw an error
} catch (error) {
  console.error("An error occurred:", error);
  // Log the error
  // Send error details to a server for analysis (optional)
}

Dealing with bugs is 💩, but not with Jam.

Capture bugs fast, in a format that thousands of developers love.
Get Jam for free