Tackling Errors in JavaScript Like a Pro

🚨 Tackling Errors in JavaScript Like a Pro! 🚨

Error handling is not just about fixing bugs; it’s about foreseeing potential pitfalls and enhancing user experience. Mastering JavaScript error handling is pivotal for robust, resilient applications.

I’ve put together exercises to help sharpen your error-handling skills:

– Explore `try-catch-finally` to manage synchronous errors gracefully.

– Dive into asynchronous error handling with async/await patterns.

– Customize your error management strategy with different types of exceptions.

– Enhance your code’s reliability with thoughtful, scenario-specific error responses.

Why is error handling essential?

– Prevents crashing applications and data corruption.

– Improves debugging speed and efficiency.

– Increases trustworthiness and reliability of your applications.

– Enhances overall program control flow and logic.

Let’s share insights, discuss challenges, and explore best practices in JavaScript error handling. Whether you’re debugging or preemptively managing errors, your approach can significantly impact your application’s quality and user satisfaction.

#JavaScript #ErrorHandling #WebDevelopment #CodingExercises #BestPractices

Embrace the challenge, transform errors into opportunities! 🛠️💡

Exercise 1: Basic Try-Catch

Problem: Write a function that attempts to parse a given JSON string and uses a try-catch block to handle any errors that occur, printing the error to the console.

Explanation: Demonstrates basic error handling using try-catch in JavaScript, essential for managing exceptions and maintaining program flow.

Code:

function safeJSONParse(jsonString) {

 try {

 let obj = JSON.parse(jsonString);

 console.log(obj);

 } catch (error) {

 console.error(“Failed to parse JSON:”, error);

 }

}

safeJSONParse(‘{“valid”: true}’); // Should print the object

safeJSONParse(‘{“invalid”: true’); // Should print an error message

Exercise 2: Finally Block

Problem: Augment the previous JSON parsing function by adding a finally block that prints “Parsing attempt finished.” whether parsing succeeds or fails.

Explanation: Shows the use of the finally block, which executes after try and catch blocks, regardless of the result, useful for cleaning up resources or finalizing operations.

Code:

function safeJSONParseWithFinally(jsonString) {

 try {

 let obj = JSON.parse(jsonString);

 console.log(obj);

 } catch (error) {

 console.error(“Failed to parse JSON:”, error);

 } finally {

 console.log(“Parsing attempt finished.”);

 }

}

safeJSONParseWithFinally(‘{“valid”: true}’);

safeJSONParseWithFinally(‘{“invalid”: true’);

Exercise 3: Custom Error

Problem: Create a custom error type ValidationError and throw it in a function if a provided string is not a valid email address. Catch and log this error.

Explanation: Introduces creating and using custom error types for more specific error handling.

Code:

class ValidationError extends Error {

 constructor(message) {

 super(message);

 this.name = “ValidationError”;

 }

}

function validateEmail(email) {

 if (!email.includes(“@”)) {

 throw new ValidationError(“This is not a valid email.”);

 }

 console.log(“Valid email:”, email);

}

try {

 validateEmail(“not-an-email”);

} catch (error) {

 if (error instanceof ValidationError) {

 console.error(“Validation Error:”, error.message);

 } else {

 console.error(“Unknown Error:”, error);

 }

}

Exercise 4: Error Propagation

Problem: Write two functions, parseUser and displayUser, where parseUser can throw a SyntaxError and displayUser catches any errors, logging them. displayUser should call parseUser.

Explanation: Demonstrates error propagation from one function to another and how caught errors can be handled in JavaScript.

Code:

function parseUser(jsonString) {

 return JSON.parse(jsonString); // This can throw a SyntaxError

}

function displayUser(jsonString) {

 try {

 let user = parseUser(jsonString);

 console.log(“User data:”, user);

 } catch (error) {

 console.error(“Error displaying user:”, error);

 }

}

displayUser(‘{“name”: “Alice”}’); // Should work

displayUser(‘{“name”:’); // Should catch and log SyntaxError

Exercise 5: Nested Try-Catch

Problem: Write a function with nested try-catch blocks: the inner block handles JSON parsing, and the outer block handles other types of errors.

Explanation: Shows the use of nested try-catch for handling different layers or types of errors in complex functions.

Code:

function complexOperation(jsonString) {

 try { // Outer try for general errors

 try { // Inner try for JSON parsing

 let result = JSON.parse(jsonString);

 console.log(“Parsed JSON:”, result);

 } catch (parsingError) {

 console.error(“JSON parsing failed:”, parsingError);

 throw new Error(“Failed operation”); // Rethrowing to handle it in the outer catch

 }

 } catch (generalError) {

 console.error(“Operation failed:”, generalError);

 }

}

complexOperation(‘{“valid”: “JSON”}’);

complexOperation(‘Invalid JSON’);

Exercise 6: Using Throw with Conditions

Problem: Write a function that throws a RangeError if a given number is not between 1 and 10, then write code that calls this function and catches the error.

Explanation: Demonstrates throwing custom errors based on specific conditions and how to appropriately catch and handle them.

Code:

function checkNumber(num) {

 if (num < 1 || num > 10) {

 throw new RangeError(“The number must be between 1 and 10.”);

 }

 console.log(“Valid number:”, num);

}

try {

 checkNumber(15);

} catch (error) {

 console.error(error.message);

}

Exercise 7: Asynchronous Error Handling

Problem: Write an async function that uses a try-catch block to handle errors for a fetch request to an invalid URL.

Explanation: Teaches error handling in asynchronous functions, particularly with promises and async/await syntax.

Code:

async function fetchData() {

 try {

 let response = await fetch(‘https://invalidurl’);

 console.log(“Data received:”, await response.json());

 } catch (error) {

 console.error(“Failed to fetch data:”, error);

 }

}

fetchData();

Exercise 8: Rejection Handling in Promises

Problem: Handle a rejected promise using .catch by simulating a failed database call that returns a promise.

Explanation: Shows handling of rejected promises, a common pattern in asynchronous JavaScript error handling.

Code:

function fakeDbCall() {

 return new Promise((resolve, reject) => {

 setTimeout(() => reject(new Error(“Database connection failed”)), 1000);

 });

}

fakeDbCall().catch(error => {

 console.error(error.message);

});

Exercise 9: Try-Catch with Async/Await in Loops

Problem: Use a loop to make multiple fetch calls within an async function, using try-catch to handle errors for each call individually.

Explanation: Explores handling errors in asynchronous loops, ensuring one error doesn’t break the entire loop’s execution.

Code:

async function fetchMultipleUrls(urls) {

 for (let url of urls) {

 try {

 let response = await fetch(url);

 console.log(`${url}: Success`);

 } catch (error) {

 console.error(`${url}: Failed to fetch`, error);

 }

 }

}

fetchMultipleUrls([‘https://jsonplaceholder.typicode.com/posts/1’, ‘https://invalidurl’]);

Exercise 10: Handling Multiple Errors

Problem: Create a function that can throw different types of errors based on input and write a try-catch block that handles each specific error type differently.

Explanation: Shows handling multiple specific errors differently based on their type or message.

Code:

function processInput(input) {

 if (typeof input !== ‘string’) {

 throw new TypeError(“Input must be a string”);

 } else if (input === “”) {

 throw new Error(“Input cannot be empty”);

 }

 console.log(“Input processed:”, input);

}

try {

 processInput(123);

} catch (error) {

 if (error instanceof TypeError) {

 console.error(“Type Error:”, error.message);

 } else if (error.message === “Input cannot be empty”) {

 console.error(“Empty Input Error:”, error.message);

 } else {

 console.error(“Unknown Error:”, error.message);

 }

}