JavaScript Exception Handling

When something unexpected goes wrong while your program runs, JavaScript creates an exception. Exceptions are errors that interrupt normal program flow. In this section, we’ll learn how to handle these errors using try, catch, finally, and throw. This helps your code deal with problems gracefully without crashing.

We’ll cover how to catch exceptions, understand the error object, ensure certain code runs no matter what, and create custom exceptions.



Using try and catch for Exception Handling

The try block lets you run code that might throw an error. If an error happens, the code stops inside try and moves to the catch block, where you can handle the error and keep your program running.

Basic Syntax of try-catch

Here’s an example where we call a function that doesn't exist, causing a runtime error:

javascript
try {
  // This causes a ReferenceError because the function doesn't exist
  nonExistentFunction();
} catch (error) {
  // We catch and handle the error here
  console.log("An error occurred:", error.message);
}

Output:

An error occurred: nonExistentFunction is not defined

How It Works

When the code inside try throws a ReferenceError, it immediately stops and jumps to the catch block. This way, the program doesn't crash, and we can handle the error, like showing a message.

Catching Other Common Errors

JavaScript throws different errors such as ReferenceError, TypeError, or SyntaxError. Here's an example that causes a TypeError by trying to access a property of null:

javascript
try {
  let obj = null;
  console.log(obj.name); // This causes a TypeError
} catch (error) {
  console.log("Caught an error:", error.message);
}

Output:

Caught an error: Cannot read properties of null (reading 'name')

Important Notes

  • try-catch only catches runtime errors: It does not catch syntax errors (errors in code that prevent it from running at all).
  • Use try-catch to keep your app running: Without it, JavaScript will stop running when an error occurs.

Using finally for Cleanup

The finally block runs after the try and catch blocks, no matter if an error was thrown or not. It’s great for cleanup tasks like closing connections or resetting things.

Syntax of finally

Place the finally block after try and catch. The code inside finally will always run.

try {
  let data = JSON.parse('{"name": "Jane"}');
  console.log("Name:", data.name);
} catch (error) {
  console.log("Error parsing JSON:", error.message);
} finally {
  console.log("Finished processing input.");
}

Explanation:

The try block parses JSON. If it fails, catch handles the error. No matter what, the finally block runs, letting us know the process is done.

Example: Ensuring Cleanup with finally

Here’s an example where finally makes sure cleanup happens even when an error occurs:

function processData() {
  try {
    // Simulate an error
    let result = 10 / 0;
    if (!isFinite(result)) {
      throw new Error("Division resulted in Infinity.");
    }
  } catch (error) {
    console.log("Error:", error.message);
  } finally {
    console.log("Cleanup: Closing connections or releasing memory.");
  }
}

processData();

Output:

Error: Division resulted in Infinity.
Cleanup: Closing connections or releasing memory.

When to Use finally

Use finally when you want to guarantee some code runs no matter what, for example:

  • Closing file or network connections
  • Resetting UI states or loading indicators
  • Releasing system or app resources
  • Cleaning up temporary data or memory

Understanding the Error Object

When an error occurs, JavaScript creates an Error object that contains useful details about what went wrong.

Common Properties

  • message: A description of the error.
  • name: The type of error (e.g., ReferenceError, TypeError).
  • stack: A stack trace showing where the error happened (useful for debugging).

Example

try {
  throw new Error("Something went wrong!");
} catch (error) {
  console.log(error.name);    // "Error"
  console.log(error.message); // "Something went wrong!"
  console.log(error.stack);   // Stack trace (varies by environment)
}

Example 1: Handling a Missing Function Call with try-catch

You can use a try-catch block to handle unexpected errors, such as calling a function that doesn’t exist. This prevents your program from crashing and allows you to respond gracefully to the error.

javascript
// Attempting to call a function that doesn't exist
try {
    nonExistentFunction(); // This will throw a ReferenceError
} catch (error) {
    console.log("Caught an error:", error.message);
}

How It Works:

  • nonExistentFunction(): This line throws a ReferenceError because the function has not been defined.
  • The try block wraps the risky code that might throw an error.
  • The catch block captures the error object and logs a friendly message to the console instead of letting the app crash.

Output

Caught an error: nonExistentFunction is not defined

Example 2: Handling a TypeError when Accessing a Property on null

In this example, we try to access a property on a null value, which would normally cause a crash. Using a try-catch block, we can handle this gracefully.

javascript
// Trying to access a property on null
try {
    let user = null;
    console.log(user.name); // This will throw a TypeError
} catch (error) {
    console.log("Caught an error:", error.message);
}

How It Works:

  • let user = null;: The variable is explicitly set to null.
  • user.name: Attempting to access a property of null throws a TypeError.
  • The catch block captures the error and logs an appropriate message to the console.

Output

Caught an error: Cannot read properties of null (reading 'name')

Example 3: Handling Invalid JSON with try-catch-finally

When parsing JSON, you can use a try-catch-finally structure to catch errors and also run code afterward regardless of whether an error occurred. The finally block is often used for cleanup or logging.

javascript
// Invalid JSON string
const badJson = '{ "name": "Jane", age: 25 }'; // Incorrect format (age should be in quotes)

try {
    const data = JSON.parse(badJson);
    console.log("Parsed data:", data);
} catch (error) {
    console.log("JSON parsing error:", error.message);
} finally {
    console.log("Finished attempting to parse JSON.");
}

How It Works:

  • badJson is an incorrectly formatted JSON string (missing quotes around age).
  • JSON.parse(badJson) throws a SyntaxError.
  • The catch block logs the parsing error.
  • The finally block runs no matter what—perfect for logging or cleanup tasks.

Output

JSON parsing error: Unexpected token a in JSON at position  twenty-something
Finished attempting to parse JSON.

Frequently Asked Questions

What is exception handling in JavaScript?

Exception handling in JavaScript is the process of catching and managing errors during program execution using try, catch, finally, and throw.


When should I use try-catch in JavaScript?

Use try-catch when you anticipate code that might throw a runtime error, such as when parsing JSON, accessing APIs, or working with user input.


Can I throw custom errors in JavaScript?

Yes, you can use throw new Error("message") to raise your own exceptions, or define custom error classes for more descriptive control flow.


Does the finally block always execute in JavaScript?

Yes, the finally block runs after the try and catch blocks, whether an error occurred or not. It's ideal for cleanup logic.


What happens if an error is not caught?

If an error isn't caught using try-catch, it can terminate script execution and log an error to the console. This may disrupt the user experience or crash part of the application.



What's Next?

Coming up next, we’ll dive into how JavaScript handles errors using throw statements. You’ll learn how to create and manage exceptions so your programs can handle unexpected situations more smoothly. Don’t worry—it’s easier than it sounds, and we’ll walk through it step by step!