Handling errors in Node.js is crucial for creating robust and reliable applications. Here’s a comprehensive guide on how to handle errors effectively in Node.js.
1. Types of Errors
Errors in Node.js can be broadly categorized into three types:
- Synchronous Errors: These occur during the execution of synchronous code.
- Asynchronous Errors: These occur in asynchronous operations, such as callbacks, promises, and async/await.
- Operational Errors: These are anticipated errors such as network issues, invalid user input, etc.
- Programmer Errors: Bugs in the code, such as undefined variables, type errors, etc.
2. Basic Error Handling
Try-Catch Block
Use try-catch blocks to handle synchronous errors.
try {
// Code that may throw an error
let result = someFunction();
} catch (error) {
// Handle the error
console.error('Error occurred:', error.message);
}
Callback Error Handling
Pass errors to the callback function to handle errors in asynchronous code.
function someAsyncFunction(callback) {
fs.readFile('/file-does-not-exist', (err, data) => {
if (err) {
return callback(err);
}
callback(null, data);
});
}
someAsyncFunction((err, data) => {
if (err) {
console.error('Error occurred:', err.message);
} else {
console.log(data);
}
});
3. Handling Promises
Using `.catch()`
Handle errors in promises with `.catch()`.
somePromiseFunction()
.then(result => {
// Handle result
})
.catch(error => {
// Handle error
console.error('Error occurred:', error.message);
});
Using `try-catch` with `async/await`
Handle errors in async functions using `try-catch`.
async function someAsyncFunction() {
try {
let result = await somePromiseFunction();
// Handle result
} catch (error) {
// Handle error
console.error('Error occurred:', error.message);
}
}
someAsyncFunction();
4. Global Error Handling
Uncaught Exceptions
Handle uncaught exceptions globally.
process.on('uncaughtException', (error) => {
console.error('Uncaught Exception:', error.message);
// Consider shutting down the process safely
});
Unhandled Promise Rejections
Handle unhandled promise rejections globally.
process.on('unhandledRejection', (reason, promise) => {
console.error('Unhandled Rejection at:', promise, 'reason:', reason);
// Consider shutting down the process safely
});
5. Creating Custom Error Classes
Create custom error classes for more specific error handling.
class CustomError extends Error {
constructor(message) {
super(message);
this.name = 'CustomError';
}
}
try {
throw new CustomError('This is a custom error');
} catch (error) {
console.error(error.name); // CustomError
console.error(error.message); // This is a custom error
}
6. Error Handling Middleware in Express.js
In an Express.js application, use error-handling middleware to handle errors.
const express = require('express');
const app = express();
// Middleware to handle errors
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
// Example route that triggers an error
app.get('/', (req, res) => {
throw new Error('BROKEN'); // Express will catch this on its own
});
app.listen(3000, () => {
console.log('Server is running on port 3000');
});
7. Best Practices
- Graceful Shutdown: Ensure the application can shut down gracefully when an error occurs.
- Logging: Use proper logging mechanisms (e.g., Winston, Bunyan) to log errors.
- Validation: Validate inputs to prevent errors.
- Monitoring: Use monitoring tools (e.g., New Relic, Sentry) to keep track of errors in production.
By following these practices and utilizing the different error-handling mechanisms provided by Node.js, you can create resilient applications that can handle errors gracefully and maintain stability.
Further, if you have any questions, please visit our website, Gurulabs Website Design Agency.