[Roadmap_Node] 4_Core Concepts

Introduction

Node.js introduces some core concepts that set it apart from traditional JavaScript execution in web browsers and provide the foundation for building powerful server-side applications. Here’s a breakdown of some key aspects:

1. Event-Driven Architecture:

2. Non-Blocking I/O (Input/Output):

3. Callbacks and Promises:

const fs = require("fs");

// Function that returns a promise to read a file
function readFilePromise(filePath) {
  return new Promise((resolve, reject) => {
    fs.readFile(filePath, "utf-8", (err, data) => {
      if (err) {
        reject(err); // Reject the promise if there's an error
      } else {
        resolve(data); // Resolve the promise with the file data
      }
    });
  });
}

// Usage of the promise function
const filePath = "my-file.txt";

readFilePromise(filePath)
  .then((data) => {
    console.log("File content:", data);
  })
  .catch((err) => {
    console.error("Error reading file:", err);
  });

console.log("This line is executed before the file is read"); // Not blocked

4. Streams:

const fs = require("fs");

const readableStream = fs.createReadStream("my-file.txt");

readableStream.on("data", (chunk) => {
  console.log(chunk.toString());
});

readableStream.on("end", () => {
  console.log("Finished reading the file");
});

readableStream.on("error", (err) => {
  console.error("Error reading file:", err);
});

5. Modules (CommonJS vs. ES6 Modules):

Here is an example of commonjs:

// Function to be exported
function add(a, b) {
  return a + b;
}

// Export the function using module.exports
module.exports = add;
const add = require("./commonJSModule"); // Import using require

const result = add(5, 3);
console.log(result); // Output: 8

Here is the counterpart using ES6 modules:

// Function to be exported
export function add(a, b) {
  return a + b;
}
import { add } from "./es6Module"; // Named import using import

const result = add(5, 3);
console.log(result); // Output: 8

6. Asynchronous Programming Patterns:

Here is an example with its proper explanation:

JavaScript;
const https = require("https");

// Function to fetch data using async/await
async function fetchData(url) {
  const response = await https.get(url); // Make the request (await the response)

  if (response.statusCode !== 200) {
    throw new Error(
      `API request failed with status code: ${response.statusCode}`
    );
  }

  const data = await response.json(); // Parse the JSON response (await the parsing)
  return data;
}

// Usage of the async function
const apiUrl = "https://api.example.com/data";

(async () => {
  try {
    const apiData = await fetchData(apiUrl);
    console.log("API data:", apiData);
  } catch (error) {
    console.error("Error fetching data:", error);
  }
})();

console.log("This line is executed before the API call finishes");

Explanation:

  1. fetchData Function:

    • This function is declared as async to enable the use of await.
    • It takes the API URL as input.
    • It uses https.get to make the API request. We await the response object to ensure the request finishes before proceeding.
    • It checks the response status code. If not 200 (success), it throws an error.
    • It uses response.json() to parse the JSON response from the API. Again, we await the parsing to ensure it’s complete.
    • It returns the parsed data.
  2. Using Async/Await:

    • We wrap our code in an Immediately Invoked Function Expression (IIFE) with async () => { ... }. This allows us to use await within the function.
    • Inside the function, we try to fetch data using await fetchData(apiUrl). We await the result of the fetchData function, which in turn awaits the API request and response parsing.
    • We handle the response data in the then block (implicit with try...catch).
    • We handle any errors thrown during the process in the catch block.
  3. Non-Blocking Behavior:

    • The line console.log('This line is executed before the API call finishes'); demonstrates non-blocking behavior. The main thread doesn’t wait for the API call to complete before executing this line.

Conclusion

These core concepts form the foundation of Node.js development. By understanding event-driven architecture, non-blocking I/O, and asynchronous programming mechanisms, you can build scalable and responsive server-side applications that efficiently handle concurrent requests and real-time interactions.

See you on the next post.

Sincerely,

Eng. Adrian Beria