try-catch β Mastering Basic Error Handling
After completing this topic
You will understand how try-catch works and be able to determine where to handle errors.
Errors Halt Program Execution
const data = JSON.parse("not json");
console.log("This line will not be executed");If JSON.parse throws an error, all code below it will not be executed. In a browser, the script execution will stop.
Handling Errors with try-catch
try {
const data = JSON.parse("not json");
} catch (error) {
console.log("Parsing failed:", error.message);
}
console.log("This line will be executed");If an error occurs within the try block, the code immediately jumps to the catch block. The program does not stop. The code after the catch block also executes normally.
The error object has .message (error message) and .stack (call stack) properties.
Throwing Errors Directly with throw
In addition to errors that JavaScript automatically throws, you can also throw errors yourself:
function divide(a, b) {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
try {
divide(10, 0);
} catch (error) {
console.log(error.message); // "Cannot divide by zero"
}throw immediately stops the function execution and passes the error to the nearest catch block. Any functions in between are skipped.
finally β Always Executed
try {
const file = openFile("data.txt");
processFile(file);
} catch (error) {
console.log("Processing failed");
} finally {
closeFile(file);
}finally always executes, whether an error occurs or not. It is used for "cleanup" tasks such as closing files, disconnecting network connections, or resetting loading states.
setLoading(true);
try {
const data = await fetchData();
setData(data);
} catch (error) {
setError(error.message);
} finally {
setLoading(false);
}async/await and try-catch
try-catch works the same way in asynchronous functions:
async function loadUser(id) {
try {
const res = await fetch(`/api/users/${id}`);
if (!res.ok) throw new Error(`HTTP ${res.status}`);
return await res.json();
} catch (error) {
console.log("Failed to load user:", error.message);
return null;
}
}By using try before await, you can catch both network errors and HTTP errors.
Where to Handle Errors
Placing try-catch blocks everywhere will make your code messy. There is a principle to follow:
Handle errors where you can recover from them. Handle errors in places where you can display an error message or retry an API call if it fails. If you only need to log the error, there is no need to handle it.
// Bad example: Catches the error but does nothing
try {
doSomething();
} catch (e) {
// Ignore
}
// Good example: Provides feedback to the user
try {
await saveData(formData);
showSuccess("Saved");
} catch (error) {
showError("Save failed: " + error.message);
}Key Takeaways
try-catchprevents errors from stopping the program.throwis used to intentionally throw errors, and the nearestcatchblock will handle them. Only usecatchin places where you can recover from the error.