Modules, async & error handling

Modules, async & error handling

Let’s explore more advanced features of Node.js, including working with modules, asynchronous programming with callbacks and Promises, and handling errors.

1. Modules in Node.js

Node.js uses a module system to organize code into reusable files. Create a simple module to handle mathematical operations:

math.js

exports.add = (a, b) => a + b;
exports.subtract = (a, b) => a - b;
exports.multiply = (a, b) => a * b;
exports.divide = (a, b) => (b !== 0 ? a / b : 'Cannot divide by zero');

Now, use this module in your main application file (app.js):

app.js

const math = require('./math');

console.log(math.add(5, 3));       // Output: 8
console.log(math.subtract(10, 4));  // Output: 6
console.log(math.multiply(2, 6));    // Output: 12
console.log(math.divide(8, 2));      // Output: 4
console.log(math.divide(5, 0));      // Output: Cannot divide by zero

2. Asynchronous Programming with Callbacks

Node.js is designed to be non-blocking and asynchronous. Here’s an example using callbacks for asynchronous file reading:

const fs = require('fs');

fs.readFile('my-file.txt', 'utf8', (err, data) => {
  if (err) {
    console.error(err);
    return;
  }
  console.log(data);
});

console.log('Reading file asynchronously...');

3. Asynchronous Programming with Promises

Promises provide a cleaner way to handle asynchronous operations. Let’s modify the previous example using Promises:

const fs = require('fs').promises;

fs.readFile('my-file.txt', 'utf8')
  .then((data) => {
    console.log(data);
  })
  .catch((err) => {
    console.error(err);
  });

console.log('Reading file asynchronously with Promises...');

4. Handling Errors

Node.js applications often deal with errors. Here’s an example of error handling using the try-catch block:

const fs = require('fs').promises;

async function readFileAsync() {
  try {
    const data = await fs.readFile('my-file.txt', 'utf8');
    console.log(data);
  } catch (err) {
    console.error(err);
  }
}

readFileAsync();
console.log('Reading file asynchronously with async/await...');

5. Events and EventEmitter

Node.js has an ‘events’ module that allows you to create custom events. Here’s a simple example:

const EventEmitter = require('events');

class MyEmitter extends EventEmitter {}

const myEmitter = new MyEmitter();

myEmitter.on('customEvent', (arg) => {
  console.log(`Custom event triggered with argument: ${arg}`);
});

myEmitter.emit('customEvent', 'Hello, EventEmitter!');

These are just a few advanced concepts in Node.js. As you continue exploring, you’ll encounter more features and patterns that make Node.js a versatile platform for building scalable and efficient applications. Happy coding!