Error Handling (try…catch…finally)
basic
Error handling is a crucial aspect of writing robust JavaScript applications. This guide explores how to effectively use try…catch…finally blocks and implement proper error handling strategies.
Basic Error Handling
1. Try…Catch Basics
try {
// Code that might throw an error
throw new Error('Something went wrong');
catch (error) {
} console.error('Error occurred:', error.message);
finally {
} // Code that always runs
console.log('This always executes');
}
// Practical example
function divideNumbers(a, b) {
try {
if (b === 0) {
throw new Error('Division by zero is not allowed');
}return a / b;
catch (error) {
} console.error('Division error:', error.message);
return null;
} }
2. Error Types
// Built-in JavaScript errors
try {
// TypeError
null.toString();
catch (error) {
} if (error instanceof TypeError) {
console.log('Type error occurred');
}
}
try {
// ReferenceError
;
nonExistentVariablecatch (error) {
} if (error instanceof ReferenceError) {
console.log('Reference error occurred');
}
}
try {
// SyntaxError (Note: Cannot be caught if in the same scope)
eval('Invalid JavaScript');
catch (error) {
} if (error instanceof SyntaxError) {
console.log('Syntax error occurred');
} }
Custom Error Classes
1. Creating Custom Errors
class ValidationError extends Error {
constructor(message) {
super(message);
this.name = 'ValidationError';
}
}
class DatabaseError extends Error {
constructor(message, query) {
super(message);
this.name = 'DatabaseError';
this.query = query;
}
}
// Usage
function validateUser(user) {
try {
if (!user.name) {
throw new ValidationError('Name is required');
}if (!user.email) {
throw new ValidationError('Email is required');
}catch (error) {
} if (error instanceof ValidationError) {
console.error('Validation failed:', error.message);
else {
} throw error; // Re-throw unexpected errors
}
} }
2. Error Hierarchies
// Base error class for application
class AppError extends Error {
constructor(message, status) {
super(message);
this.name = this.constructor.name;
this.status = status;
Error.captureStackTrace(this, this.constructor);
}
}
// Specific error types
class HttpError extends AppError {
constructor(message, status = 500) {
super(message, status);
}
}
class ValidationError extends AppError {
constructor(message, field) {
super(message, 400);
this.field = field;
}
}
// Usage
try {
throw new HttpError('Not Found', 404);
catch (error) {
} if (error instanceof HttpError) {
console.error(`${error.status}: ${error.message}`);
} }
Async Error Handling
1. Promises
// Using .catch with promises
fetchData()
.then(data => processData(data))
.catch(error => {
console.error('Error fetching data:', error);
;
})
// Chaining multiple catches
fetchData()
.then(data => processData(data))
.catch(error => {
if (error instanceof NetworkError) {
return fetchBackupData();
}throw error;
}).then(data => displayData(data))
.catch(error => {
console.error('Unrecoverable error:', error);
; })
2. Async/Await
async function fetchUserData(userId) {
try {
const user = await fetchUser(userId);
const posts = await fetchUserPosts(user.id);
return { user, posts };
catch (error) {
} console.error('Error fetching user data:', error);
throw error; // Re-throw if needed
finally {
} // Cleanup code
}
}
// Multiple try-catch blocks
async function processUserData(userId) {
try {
const user = await fetchUser(userId);
try {
await validateUser(user);
catch (validationError) {
} console.error('Validation failed:', validationError);
return null;
}
return user;
catch (error) {
} console.error('Error processing user:', error);
throw error;
} }
Error Handling Patterns
1. Error Wrapper Function
function withErrorHandling(fn) {
return async (...args) => {
try {
return await fn(...args);
catch (error) {
} console.error(`Error in ${fn.name}:`, error);
throw error;
};
}
}
// Usage
const safeOperation = withErrorHandling(async function riskyOperation() {
// Potentially risky code
; })
2. Error Handler Class
class ErrorHandler {
static handle(error, context = '') {
if (error instanceof ValidationError) {
this.handleValidationError(error, context);
else if (error instanceof DatabaseError) {
} this.handleDatabaseError(error, context);
else {
} this.handleUnknownError(error, context);
}
}
static handleValidationError(error, context) {
console.error(`Validation error in ${context}:`, error.message);
// Additional handling logic
}
static handleDatabaseError(error, context) {
console.error(`Database error in ${context}:`, error.message);
// Additional handling logic
}
static handleUnknownError(error, context) {
console.error(`Unknown error in ${context}:`, error);
// Additional handling logic
}
}
// Usage
try {
// Risky operation
catch (error) {
} .handle(error, 'UserService');
ErrorHandler }
3. Result Type Pattern
class Result {
constructor(success, data = null, error = null) {
this.success = success;
this.data = data;
this.error = error;
}
static ok(data) {
return new Result(true, data);
}
static fail(error) {
return new Result(false, null, error);
}
}
async function fetchUserData(userId) {
try {
const user = await fetchUser(userId);
return Result.ok(user);
catch (error) {
} return Result.fail(error);
}
}
// Usage
const result = await fetchUserData(123);
if (result.success) {
console.log('User:', result.data);
else {
} console.error('Error:', result.error);
}
Best Practices
- Specific Error Handling
try {
await saveUser(user);
catch (error) {
} if (error instanceof ValidationError) {
// Handle validation errors
else if (error instanceof DatabaseError) {
} // Handle database errors
else {
} // Handle unknown errors
} }
- Cleanup with Finally
let connection;
try {
= await database.connect();
connection await connection.query('SELECT * FROM users');
catch (error) {
} console.error('Database error:', error);
finally {
} if (connection) {
await connection.close();
} }
- Error Recovery Strategies
async function fetchDataWithRetry(url, maxRetries = 3) {
for (let attempt = 1; attempt <= maxRetries; attempt++) {
try {
return await fetch(url);
catch (error) {
} if (attempt === maxRetries) throw error;
await delay(1000 * attempt); // Exponential backoff
}
} }