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:
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);
}
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
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
:
try {
let obj = null;
console.log(obj.name); // This causes a TypeError
} catch (error) {
console.log("Caught an error:", error.message);
}
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')
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.");
}
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();
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.
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)
}
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.
// 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);
}
// 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
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.
// 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);
}
// 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')
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.
// 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.");
}
// 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.
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?
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?
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?
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?
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?
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!