๐จ How to Handle Unhandled Exceptions & Unhandled Promise Rejections in JavaScript and React
One of the biggest differences between a demo app and a production app is error handling.
A good application doesn't just work when everything is fineโit fails gracefully when something goes wrong.
๐ง 1๏ธโฃ What is an Unhandled Exception?
An unhandled exception is an error that is thrown but never caught.
Example:
function divide(a, b) {
if (b === 0) {
throw new Error("Cannot divide by zero");
}
return a / b;
}
divide(10, 0); // โ Uncaught Error
Since there's no try...catch, the application may crash or stop executing that code path.
โ
Handle It with try...catch
try {
divide(10, 0);
} catch (error) {
console.error(error.message);
}
โ Prevents the app from crashing unexpectedly.
๐ง 2๏ธโฃ What is an Unhandled Promise Rejection?
When a Promise rejects and no .catch() (or try...catch with await) handles it.
fetch("/api/users")
.then(res => res.json());
// โ No .catch()
Or:
async function getUsers() {
const res = await fetch("/api/users");
return res.json();
}
// โ No try...catch
โ Handle Async Errors Properly
async function getUsers() {
try {
const res = await fetch("/api/users");
if (!res.ok) {
throw new Error("Failed to fetch users");
}
return await res.json();
} catch (error) {
console.error(error);
}
}
โ๏ธ 3๏ธโฃ Handling Errors in React
React Error Boundaries catch:
โ Rendering errors
โ Lifecycle errors
โ Constructor errors
Example:
<ErrorBoundary>
<Dashboard />
</ErrorBoundary>
๐จ Error Boundaries DO NOT Catch
โ Event handler errors
<button onClick={() => {
throw new Error("Boom");
}} />
โ Async errors
setTimeout(() => {
throw new Error("Boom");
}, 1000);
โ Promise rejections
You must handle these yourself.
๐ 4๏ธโฃ Global Error Handling (Browser)
You can listen for uncaught JavaScript errors:
window.addEventListener("error", (event) => {
console.error("Unhandled Exception:", event.error);
});
Useful for:
- Logging
- Monitoring
- Crash reporting
๐ 5๏ธโฃ Global Promise Rejection Handling
Handle promises that nobody caught:
window.addEventListener("unhandledrejection", (event) => {
console.error("Unhandled Promise:", event.reason);
});
This is commonly used to send errors to monitoring tools.
๐ 6๏ธโฃ Log Errors to Monitoring Services
In production, don't just use:
console.error(error);
Use tools like:
- Sentry
- Bugsnag
- Datadog
These provide:
โ Stack traces
โ User sessions
โ Browser info
โ Release tracking
๐จ Common Mistakes
โ Empty catch blocks
try {
// code
} catch {}
๐ Silently ignores errors.
โ Swallowing errors
catch (error) {
// do nothing
}
Always log or handle them appropriately.
โ Assuming fetch() throws for HTTP errors
const res = await fetch("/users");
A 404 or 500 does not throw. You should check:
if (!res.ok) {
throw new Error("Request failed");
}
๐ก Senior-Level Insight
A good error-handling strategy has multiple layers:
-
Local handling:
try...catchfor recoverable operations. - Component handling: Error Boundaries for UI rendering errors.
-
Global handling:
window.onerrorandwindow.onunhandledrejection. -
Monitoring: Send errors to a centralized service instead of relying on
console.error.
The goal isn't to hide errorsโit's to capture them, recover when possible, and give users a graceful experience.
๐ฏ Interview One-Liner
Handle synchronous exceptions using
try...catch, asynchronous errors using.catch()ortry...catchwithasync/await, use React Error Boundaries for rendering errors, and implement global error listeners and monitoring tools to capture uncaught exceptions and promise rejections in production.
Top comments (0)