Asynchronous Error Handling in JavaScript
Handle async errors with promises, async/await, and modern error handling patterns
Introduction
Asynchronous error handling differs fundamentally from synchronous error handling. Traditional try/catch doesn't work with async operations like timers, events, or promises.
Why Async Errors Are Different
Async operations execute on different tracks than synchronous code:
// ❌ This won't work
try {
setTimeout(() => {
throw new Error('Something went wrong!');
}, 1000);
} catch (error) {
// Never reaches here - try/catch is long gone
}
Error Handling Patterns
Timers
Handle errors inside the callback:
setTimeout(() => {
try {
riskyOperation();
} catch (error) {
console.error('Timer error:', error);
}
}, 1000);
Event Handlers
button.addEventListener('click', () => {
try {
doSomething();
} catch (error) {
console.error('Event error:', error);
}
});
Promises
Use .catch():
fetch('/api/data')
.then((res) => res.json())
.catch((error) => console.error(error));
Async/Await
Use try/catch:
async function fetchData() {
try {
const response = await fetch('/api/data');
return await response.json();
} catch (error) {
console.error('Fetch failed:', error);
throw error;
}
}
Global Error Handlers
Window.onerror
window.onerror = (message, source, lineno, colno, error) => {
console.error('Global error:', error);
logToService(error);
return true;
};
Unhandled Promise Rejections
window.onunhandledrejection = (event) => {
console.error('Unhandled rejection:', event.reason);
event.preventDefault();
};
Best Practices
Always Handle Promise Rejections
// ✅ Always add catch
fetch('/api/data')
.then((res) => res.json())
.catch((error) => console.error(error));
Use Finally for Cleanup
async function loadData() {
try {
return await fetchData();
} catch (error) {
console.error('Load failed:', error);
} finally {
hideLoadingSpinner(); // Always runs
}
}
Provide Context
async function fetchUser(userId) {
try {
const response = await fetch(`/api/users/${userId}`);
return await response.json();
} catch (error) {
throw new Error(`Failed to fetch user ${userId}: ${error.message}`);
}
}
Common Pitfalls
Forgetting .catch()
// ❌ Unhandled rejection
fetch('/api/data').then((res) => res.json());
// ✅ Handle errors
fetch('/api/data')
.then((res) => res.json())
.catch((error) => console.error(error));
Swallowing Errors
// ❌ Silent failure
fetch('/api/data').catch(() => {});
// ✅ Log errors
fetch('/api/data').catch((error) => {
console.error('Fetch failed:', error);
});
Conclusion
Use .catch() for promises, try/catch with async/await, and global handlers as safety nets. Always handle errors gracefully.
#javascript #error-handling #async #promises