Promise error handling is an essential skill when working with Promises. Proper error handling ensures program robustness and prevents uncaught errors from causing program crashes.
Basic Methods of Error Handling
1. Using .catch() Method
.catch() is the primary method for Promise error handling, catching errors thrown anywhere in the chain:
javascriptPromise.resolve() .then(() => { throw new Error('Error occurred'); }) .catch(error => { console.error('Caught error:', error.message); });
2. Handling in the Second Parameter of .then()
The .then() method can accept two parameters: success callback and failure callback:
javascriptPromise.resolve() .then( result => console.log('Success:', result), error => console.error('Failure:', error.message) );
Note: This error handling only catches errors from the previous Promise and won't catch errors later in the chain.
Error Propagation Mechanism
Errors Propagate Down the Promise Chain
javascriptPromise.resolve() .then(() => { throw new Error('First error'); }) .then(() => { console.log('This line will not execute'); }) .then(() => { console.log('This line will also not execute'); }) .catch(error => { console.error('Finally caught:', error.message); // Output: Finally caught: First error });
Errors Can Be Recovered After Being Caught
javascriptPromise.resolve() .then(() => { throw new Error('Error occurred'); }) .catch(error => { console.error('Caught error:', error.message); return 'Recovered value'; // Return a value, chain can continue }) .then(value => { console.log('Continue execution:', value); // Output: Continue execution: Recovered value });
Common Error Handling Scenarios
1. Network Request Error Handling
javascriptfetch('/api/data') .then(response => { if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return response.json(); }) .then(data => { console.log('Data:', data); }) .catch(error => { console.error('Request failed:', error.message); // Can show error message to user here showErrorToUser('Data loading failed, please try again later'); });
2. Error Handling for Multiple Promises
javascriptPromise.all([promise1, promise2, promise3]) .then(results => { console.log('All successful:', results); }) .catch(error => { console.error('At least one failed:', error.message); });
3. Handling Partial Failures with Promise.allSettled
javascriptPromise.allSettled([promise1, promise2, promise3]) .then(results => { results.forEach((result, index) => { if (result.status === 'fulfilled') { console.log(`Promise ${index} succeeded:`, result.value); } else { console.error(`Promise ${index} failed:`, result.reason); } }); });
Error Handling Best Practices
1. Always Add Error Handling
javascript// Not recommended: no error handling fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)); // Recommended: add error handling fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error));
2. Use finally for Cleanup
javascriptlet isLoading = true; fetch('/api/data') .then(response => response.json()) .then(data => console.log(data)) .catch(error => console.error(error)) .finally(() => { isLoading = false; console.log('Request completed, whether successful or failed'); });
3. Make Error Handling Specific
javascript// Not recommended: generic error handling Promise.resolve() .catch(error => { console.error('Error occurred'); }); // Recommended: specific error handling Promise.resolve() .catch(error => { if (error instanceof NetworkError) { console.error('Network error:', error.message); } else if (error instanceof ValidationError) { console.error('Validation error:', error.message); } else { console.error('Unknown error:', error.message); } });
4. Consider Error Recovery Strategies
javascriptasync function fetchDataWithRetry(url, maxRetries = 3) { for (let i = 0; i < maxRetries; i++) { try { const response = await fetch(url); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { console.error(`Attempt ${i + 1} failed:`, error.message); if (i === maxRetries - 1) { throw error; // Last attempt failed, throw error } // Wait before retrying await new Promise(resolve => setTimeout(resolve, 1000 * (i + 1))); } } }
Error Handling in async/await
Using try/catch
javascriptasync function fetchData() { try { const response = await fetch('/api/data'); const data = await response.json(); console.log('Data:', data); } catch (error) { console.error('Error:', error.message); // Error handling logic } }
Catching Specific Errors
javascriptasync function fetchData() { try { const response = await fetch('/api/data'); if (!response.ok) { throw new Error(`HTTP error! status: ${response.status}`); } return await response.json(); } catch (error) { if (error.name === 'TypeError') { console.error('Network connection problem'); } else if (error.message.includes('HTTP error')) { console.error('Server error'); } else { console.error('Unknown error:', error); } throw error; // Can choose to rethrow error } }
Uncaught Promise Errors
Global Error Handling
javascript// Handle uncaught Promise errors window.addEventListener('unhandledrejection', event => { console.error('Uncaught Promise error:', event.reason); // Can log error or show error message here event.preventDefault(); // Prevent default error output }); // In Node.js environment process.on('unhandledRejection', (reason, promise) => { console.error('Uncaught Promise error:', reason); });
Common Error Handling Pitfalls
1. Forgetting to Add catch in Chain
javascript// Dangerous: no error handling Promise.reject('Error occurred') .then(result => console.log(result)); // Error will bubble to global, potentially causing program crash // Safe: add error handling Promise.reject('Error occurred') .then(result => console.log(result)) .catch(error => console.error(error));
2. Forgetting to Rethrow Errors in catch
javascript// Potentially problematic: error is swallowed Promise.reject('Error occurred') .catch(error => { console.error('Caught error:', error); // Forgot to rethrow, subsequent code will continue executing }) .then(() => { console.log('This will execute even though there was an error earlier'); }); // Recommended: decide whether to rethrow based on situation Promise.reject('Error occurred') .catch(error => { console.error('Caught error:', error); // If error cannot be recovered, rethrow throw error; });
3. Mixing then's Second Parameter with catch
javascript// Not recommended: confusing Promise.resolve() .then( result => console.log('Success'), error => console.error('Failure1') ) .catch(error => console.error('Failure2')); // Recommended: use catch uniformly Promise.resolve() .then(result => console.log('Success')) .catch(error => console.error('Failure'));
Summary
- Always add error handling: Use
.catch()ortry/catch - Understand error propagation: Errors propagate down the Promise chain
- Use finally for cleanup: Put code that must execute regardless of success or failure in
finally - Make error handling specific: Handle different error types differently
- Consider error recovery: Implement retry mechanisms or fallback strategies
- Avoid swallowing errors: Ensure errors are properly handled or rethrown
- Global error monitoring: Use global error handlers to catch unhandled errors