Error Handling
- This lesson explains structured error handling in JavaScript.
Introduction to Error Handling in Asynchronous JavaScript
In real-world JavaScript applications, especially when working with:
APIs
Servers
Databases
Timers
Promises
errors are unavoidable.
If errors are not handled properly:
Application may crash
Data may be lost
Users may see blank screens
Debugging becomes difficult
Asynchronous JavaScript requires special techniques for error handling, because errors do not always behave the same way as synchronous code.
What Is an Error ?
An error is a situation where JavaScript cannot execute code correctly due to:
Invalid logic
Missing data
Network failure
Server issues
Unexpected conditions
Example:
console.log(a);
If a is not defined, JavaScript throws an error.
Why Error Handling Is Critical in Async Code
In synchronous code:
Errors can be caught easily using try...catch
In asynchronous code:
Errors may occur later
Errors may happen outside the main execution flow
Errors must be handled differently
Types of Errors in Async JavaScript
Common async errors include:
Network errors
Promise rejections
API failures
Timeout issues
Invalid responses
JSON parsing errors
Error Handling with Callbacks
Problem with Callbacks
Error Handling in Asynchronous JavaScript using Callbacks
Handles async errors using a callback with an error-first approach.
function getData(callback) {
setTimeout(() => {
callback("Error occurred", null);
}, 1000);
}
getData(function (error, data) {
if (error) {
console.log(error);
} else {
console.log(data);
}
});
Problems:
Error handling logic mixed with main logic
Code becomes hard to read
Leads to callback hell
Error Handling with Promises
Promises provide a cleaner way to handle async errors.
Handling Errors Using .catch()
Error Handling using Promises in JavaScript
Handles errors in a Promise using .catch() when the Promise is rejected.
let promise = new Promise((resolve, reject) => {
reject("Something went wrong");
});
promise
.then(result => {
console.log(result);
})
.catch(error => {
console.log(error);
});
If a promise is rejected, .catch() handles the error.
Important Rule
Any error inside a promise automatically goes to .catch()
Handling Exceptions in Promises
Automatically catches thrown errors inside a Promise using .catch().
new Promise((resolve, reject) => {
throw new Error("Failure");
})
.catch(error => {
console.log(error.message);
});
Error Handling in Promise Chaining
Catches errors from any step in a Promise chain using a single .catch() block.
fetchData()
.then(data => {
return processData(data);
})
.then(result => {
console.log(result);
})
.catch(error => {
console.log("Error:", error);
});
One .catch() can handle errors from the entire chain
Prevents application crash
What Happens Without .catch()
fetchData()
.then(data => {
console.log(data);
});
If an error occurs:
Unhandled promise rejection
Application may break
Console warnings appear
Error Handling with async and await
async/await makes async code look synchronous, but error handling must still be done carefully.
Using try...catch with Async Code
Error Handling with Async/Await
Uses try...catch to handle errors in asynchronous code with async/await.
async function getUserData() {
try {
let response = await fetch("https://api.example.com/user");
let data = await response.json();
console.log(data);
} catch (error) {
console.log("Error:", error);
}
}
getUserData();
Why try...catch Works Here
await pauses execution
Rejected promises throw errors
catch block captures them
Handling Network Errors vs API Errors
Checking HTTP Response Status in Async/Await
Validates API response status and throws an error if the request fails, handled using try...catch.
async function fetchData() {
try {
let response = await fetch("https://api.example.com/data");
if (!response.ok) {
throw new Error("HTTP Error: " + response.status);
}
let data = await response.json();
console.log(data);
} catch (error) {
console.log("Fetch failed:", error.message);
}
}
Handling Multiple Async Operations with Promise.all
Executes multiple async tasks in parallel and handles errors if any request fails.
async function loadAll() {
try {
let [user, posts] = await Promise.all([
fetchUser(),
fetchPosts()
]);
console.log(user, posts);
} catch (error) {
console.log("One of the requests failed");
}
}
If any promise fails, control goes to catch.
Common Async Error Handling Mistakes
Mistake 1: Using try...catch Without await
try {
fetchData();
} catch (error) {
console.log(error);
}
This will NOT catch async errors.
Correct way:
await fetchData();
Mistake 2: Forgetting .catch()
Unhandled promise rejections can crash applications.
Mistake 3: Silent Errors
catch (error) {}
Always log or handle errors meaningfully.
Best Practices for Async Error Handling
Always handle promise rejections
Use try...catch with async/await
Validate API responses
Log errors clearly
Show user-friendly messages
Avoid empty catch blocks
Clean up resources when errors occur
User-Friendly Error Handling in Async Operations
Provides a simple user-friendly message instead of exposing technical errors during failures.
async function loginUser() {
try {
let response = await fetch("/login");
if (!response.ok) {
throw new Error("Login failed");
}
console.log("Login successful");
} catch (error) {
console.log("Please try again later");
}
}
Users see friendly messages, developers see logs.
Error Handling Strategy
Detect error early
Handle error gracefully
Log error for debugging
Prevent app crash
Inform user properly