0% found this document useful (0 votes)
12 views

NODE JSNEW

Uploaded by

munnugaming48
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
12 views

NODE JSNEW

Uploaded by

munnugaming48
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 38

NODE JS

1. Introduction to Node.js

 What is Node.js?
 Runtime environment
 Advantages of Node.js
 Features of Node.js

2. Node.js Architecture

 Core modules in Node.js


 Buffer class
 Event-driven programming
 Node concurrency
 Understanding the event loop (event loop, microtasks, process.nextTick)
 Libuv and thread pool
 Single-threaded nature of Node.js
 Garbage collection

3. NPM (Node Package Manager)

 npm init
 npm vs. npx
 Understanding package.json and package-lock.json
 Dev dependencies vs. dependencies
 npm start
 npm publish
 .npmrc file
 Scaffolding (e.g., express-generator)

4. Express.js and Alternatives

 Introduction to Express.js
 Features of Express.js
 Routing in Express.js
o express.Router()
o Router.all
o Dynamic routing
o Router chaining
o Query parameters vs. URL parameters
o Handling static files
 Alternatives to Express.js (e.g., Koa, Hapi, Fastify)
 Middleware in Node.js
o Application-level vs. Router-level middleware
o Common middlewares (e.g., express.json, express.urlencoded)
o Error-handling middleware
 MVC (Model-View-Controller) architecture
 View engines (e.g., EJS, Handlebars)
 Session and cookies

5. HTTP and Middleware

 HTTP vs. HTTPS


 HTTP methods (GET, POST, PUT, PATCH, DELETE, OPTIONS)
 Request and response headers
 Status codes (including 400 range)
 CORS (Cross-Origin Resource Sharing)
 res.send vs res.write vs res.end
 res.redirect
 Handling query params and path params
 HTTP OPTIONS method and preflight requests
 File response and download file
 Middleware types (application, router, error-handling)

6. Streams, Events, and Asynchronous Operations

 Streams (Readable, Writable, Duplex, Transform)


 Stream piping
 Event-driven architecture
 Event emitter and handlers
 Asynchronous operations (callbacks, promises)
 Promises and promise chaining
 Promisify
 Callbacks
 async/await

7. Advanced Express.js

 PUT vs PATCH HTTP methods (idempotency)


 Handling scope chaining (let vs. var)
 URL encoding
 Body-parser vs. express.json and express.urlencoded
 Handling cookies and sessions
 File handling using fs module (readFile vs. readFileSync)
 Reading and writing to files asynchronously

8. Concurrency, Multithreading, and Child Processes

 Node concurrency model


 Fork, spawn, exec, and execFile methods
 Child processes
 Clustering in Node.js
 process.nextTick vs setImmediate
 PM2 process manager (for managing Node applications)
 REPL (Read-Eval-Print Loop)
 Using events and child processes effectively
9. Sockets and Security

 WebSocket communication in Node.js


 Socket.io for real-time communication
 Security best practices in Node.js
 Authentication and Authorization (e.g., Passport.js)
 CSRF protection
 Encryption vs Hashing (bcrypt, crypto)
 Content Security Policy (CSP)

10. Configuration and Environment

 Environment variables and dotenv


 Process management and cron jobs
 NVM (Node Version Manager)
 Practical examples (e.g., parsing hostname using URL module and writing to a file with time)
 Domain and port handling in Node.js

11. Other Relevant Concepts

 JSON parsing and stringifying


 Blocking vs Non-blocking code
 Conditional operator vs optional chaining
 Why Node.js uses a single thread
 Understanding the thread pool and async operations
 Trace and performance tuning in Node.js
 Binary JSON (BSON)
 Using middleware effectively in large applications
 Custom middleware examples

12. Request and Response Lifecycle

 Lifecycle of an HTTP request and response


 Understanding cookies and sessions
 Changing status codes of a response
 Handling login and redirection (e.g., don’t show login for logged-in users)
 Path and URL handling (e.g., URL fragments)
 HTTP request payloads (can we send body payload in a GET request?)

13. Performance and Debugging

 Debugging Node.js applications


 Handling large-scale applications with Node.js
 Using event-driven programming effectively
 Performance optimization strategies (e.g., stream usage, clustering)
 Profiling and performance tuning (e.g., Trace)
 Monitoring Node.js applications with PM2
 Using the REPL for quick debugging and experimentation

14. Final Review and Practice


 Review core Node.js concepts
 Practical examples (e.g., scaffolding a new project, creating custom middleware)
 Review package.json components and dependencies
 Understanding and practicing middleware usage
 Implementing real-world use cases with Express.js
 Building a REST API from scratch
 Handling complex routing scenarios
 Event emitters and the event loop in real-world applications
1. Introduction to Node.js

 What is Node.js?

Node.js is an open-source, cross-platform JavaScript runtime environment that


allows you to run JavaScript code outside of a web browser. It is built on Chrome’s V8
JavaScript engine and is commonly used to build server-side applications.

 Runtime environment

A runtime environment is a platform that provides the necessary tools and libraries to run
programs written in a specific language. For Node.js, the runtime environment includes:

 V8 JavaScript Engine: This engine compiles JavaScript code into machine code, making it
fast and efficient.
 Node.js APIs: These are built-in modules that provide functionalities like file system access,
networking, and more.
 Event Loop: Node.js uses an event-driven, non-blocking I/O model, which allows it to
handle multiple operations concurrently without waiting for any single operation to
complete

 Advantages of Node.js

o High Performance: Node.js is built on the V8 engine, which makes it very fast.
o Scalability: Its event-driven architecture allows it to handle many connections
simultaneously.
o Single Programming Language: You can use JavaScript for both frontend and
backend development.
o Large Ecosystem: The Node Package Manager (npm) provides access to thousands
of libraries and tools.

 Features of Node.js

 Asynchronous and Event-Driven: Node.js uses an asynchronous, non-blocking


architecture, allowing multiple operations to run concurrently.
 Single-Threaded but Highly Scalable: It uses a single thread to handle multiple requests,
making it efficient and scalable.
 Cross-Platform: Node.js can run on various operating systems like Windows, Linux, and
macOS.
 Fast Execution: Built on the V8 engine, it compiles JavaScript into machine code for fast
execution.
 Rich Library of Modules: The npm registry provides a vast collection of reusable modules

2. Node.js Architecture

 Core modules in Node.js

Core modules are built-in modules that come with Node.js. They provide essential
functionalities without needing to install additional packages. Some important core
modules include:

 http: Creates an HTTP server.


 fs: Handles file system operations.
 path: Provides utilities for working with file and directory paths.
 os: Provides information about the operating system.
 events: Implements the EventEmitter class for event-driven programming

 Buffer class

The Buffer class in Node.js is used to handle binary data directly. Unlike JavaScript strings,
buffers are raw memory allocations outside the V8 heap.They are useful for dealing with
binary data, such as reading files or handling network packets

 Event-driven programming

Event-driven programming is a paradigm where the flow of the program is determined by


events like user actions, sensor outputs, or messages from other programs. In Node.js, this
is achieved using the EventEmitter class. Functions (event handlers) are executed when
specific events are emitted.

// Import the events module


const EventEmitter = require('events');

// Create an instance of EventEmitter


const myEmitter = new EventEmitter();

// Define an event handler for the 'greet' event


myEmitter.on('greet', (name) => {
console.log(`Hello, ${name}!`);
});
// Emit the 'greet' event
myEmitter.emit('greet', 'Alice'); // Output: Hello, Alice!
myEmitter.emit('greet', 'Bob'); // Output: Hello, Bob!

 Node concurrency

Node.js handles concurrency using an event-driven, non-blocking I/O model. This means
it can handle multiple operations simultaneously without waiting for any single operation
to complete. This is achieved through asynchronous programming, where tasks are
executed in the background, and callbacks are used to handle the results

 Understanding the event loop (event loop, microtasks, process.nextTick)

The event loop is a core part of Node.js that allows it to perform non-blocking I/O
operations. Here’s a breakdown:

 Event Loop: Continuously checks for and executes tasks from the event queue.
 Microtasks: Tasks that need to be executed immediately after the current operation,
like promises.
 process.nextTick: A special microtask that executes before other microtasks

 Libuv and thread pool

Libuv is a library that Node.js uses to handle asynchronous operations. It provides a thread
pool to handle tasks that cannot be executed asynchronously by the event loop, such as
file system operations. This allows Node.js to perform non-blocking I/O operations
efficiently

 Single-threaded nature of Node.js

Node.js operates on a single-threaded event loop, meaning it uses a single thread to


handle multiple requests. This is efficient for I/O-bound tasks but can be a limitation for
CPU-bound tasks. However, Node.js can still handle concurrency through its non-blocking
I/O model and the use of worker threads for CPU-intensive tasks.

 Garbage collection

Garbage collection in Node.js is managed by the V8 JavaScript engine. It automatically frees


up memory that is no longer in use, helping to prevent memory leaks and optimize
performance. The garbage collector runs periodically to clean up unused objects

3. NPM (Node Package Manager)

 npm init
npm init is a command used to create a new package.json file for your Node.js
project. This file contains metadata about your project, such as its name, version,
description, and dependencies. Running npm init will prompt you to enter this
information step-by-step.

You can also use npm init -y to create a package.json file with default values.

 npm vs. npx

npm vs. npx

 npm: Stands for Node Package Manager. It is used to install, update, and manage packages
(libraries) in your Node.js projects.
 npx: Stands for Node Package Execute. It is used to run Node.js packages without installing
them globally. This is useful for running one-off commands or tools.

 Understanding package.json and package-lock.json

1. package.json: This file contains metadata about your project and lists the dependencies
your project needs to run. It also includes scripts for common tasks like starting the server
or running tests.

2. package-lock.json: This file is automatically generated and ensures that the exact same
versions of dependencies are installed every time. It locks down the versions of all installed
packages, including nested dependencies.

 Dev dependencies vs. dependencies

1. Dependencies: These are packages required for your application to run in production. They
are listed under the dependencies section in package.json.
a. npm install express

2. Dev Dependencies: These are packages needed only during development, such as testing
frameworks or build tools. They are listed under the devDependencies section.
a. npm install --save-dev jest

 npm start
o npm start is a command used to run the start script defined in
your package.json. If no start script is defined, it defaults to running node
server.js.
{
"scripts": {
"start": "node index.js"
}
}
 npm publish

npm publish is a command used to publish your package to the npm registry,
making it available for others to install and use.

 .npmrc file

The .npmrc file is used to configure npm settings for your project or globally. You can set
registry URLs, authentication tokens, and other settings.

 Scaffolding (e.g., express-generator)

Scaffolding tools like express-generator help you quickly set up a new project with a
predefined structure. This saves time and ensures consistency .

4. Express.js and Alternatives

 What is Express.js

Express.js is a minimalist web framework for Node.js. It simplifies the process of building
web applications and APIs by providing a robust set of features and utilities. Essentially,
Express.js allows you to handle HTTP requests and responses with ease, making it a popular
choice for server-side development in JavaScript.

 Features of Express.js
 Routing in Express.js

Routing in Express.js determines how an application responds to client requests for


different URLs (or routes). It involves defining endpoints and the HTTP methods (GET, POST,
etc.) that can be used to access them.

o express.Router()

express.Router() is a function that creates a new router object. This router


object can be used to define routes separately from the main application. It helps
in organizing your code by grouping related routes together.

o Router.all

Router.all is a method that handles all HTTP methods (GET, POST, PUT, DELETE,
etc.) for a specific route. It’s useful for middleware that should apply to all types of
requests
o Dynamic routing

Dynamic routing allows you to define routes with parameters that can change.
These parameters are defined using a colon (:) and can be accessed
via req.params.

o Router chaining

Router chaining allows you to chain route handlers for a single route. This is
useful for applying multiple middleware functions in sequence.

o Query parameters vs. URL parameters

Query Parameters: Passed in the URL after the question mark (?) and are used for
optional data. Accessed via req.query

o Handling static files

Express.js can serve static files (like images, CSS, JavaScript) using
the express.static middleware. This is useful for serving assets required by
your frontend

 Alternatives to Express.js (e.g., Koa, Hapi, Fastify)

Middleware in Node.js

Middleware functions are functions that have access to the request object (req), the response
object (res), and the next middleware function in the application’s request-response cycle. They
can perform various tasks such as modifying the request or response objects, ending the request-
response cycle, or calling the next middleware function.

Application-Level vs. Router-Level Middleware

 Application-Level Middleware: This middleware is bound to an instance of the Express app


using app.use() or app.METHOD(). It applies to all routes within the application.

const express = require('express');


const app = express();
// Application-level middleware
app.use((req, res, next) => {
console.log('Time:', Date.now());
next();
});
app.get('/', (req, res) => {
res.send('Hello, World!');
});
app.listen(3000);
 Router-Level Middleware: This middleware is bound to an instance of express.Router(). It
applies only to the routes defined within that router.

const express = require('express');


const router = express.Router();

// Router-level middleware
router.use((req, res, next) => {
console.log('Request URL:', req.originalUrl);
next();
});

router.get('/user/:id', (req, res) => {


res.send(`User ID: ${req.params.id}`);
});

const app = express();


app.use('/api', router);
app.listen(3000);

Common Middlewares

 express.json(): Parses incoming requests with JSON payloads.

app.use(express.json());

 express.urlencoded(): Parses incoming requests with URL-encoded payloads.

app.use(express.urlencoded({ extended: true }));

 morgan: HTTP request logger middleware.

const morgan = require('morgan');


app.use(morgan('dev'));

 cors: Enables Cross-Origin Resource Sharing.

const cors = require('cors');


app.use(cors());

Error-Handling Middleware
o Error-handling middleware is defined with four parameters: err, req, res, and next. It is
used to catch and handle errors that occur during the request-response cycle.
JavaScript
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});
Example of Error-Handling Middleware
const express = require('express');
const app = express();

app.get('/', (req, res) => {


throw new Error('BROKEN'); // Express will catch this on its own.
});

// Error-handling middleware
app.use((err, req, res, next) => {
console.error(err.stack);
res.status(500).send('Something broke!');
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

MVC (Model-View-Controller) Architecture


The Model-View-Controller (MVC) architecture is a design pattern used to separate an
application into three main components:

 Model: Manages the data and business logic. It interacts with the database and handles data-
related operations.
 View: Handles the presentation layer. It displays the data to the user and collects user input.
 Controller: Acts as an intermediary between the Model and the View. It processes user input,
interacts with the Model, and updates the View accordingly.

This separation helps in organizing code, making it easier to manage and scale.

View Engines (e.g., EJS, Handlebars)


View engines are tools used to generate dynamic HTML content by combining templates with
data. They are commonly used in web frameworks like Express.js.

 EJS (Embedded JavaScript): Allows you to embed JavaScript code within HTML. It is simple and
easy to use.

<h1>Welcome, <%= username %>!</h1>

 Handlebars: A logic-less templating engine that focuses on simplicity. It uses placeholders and
helpers to generate dynamic content.
{{#if loggedIn}}
<p>Welcome, {{username}}!</p>
{{else}}
<a href="/login">Login</a>
{{/if}}
Both view engines help in creating dynamic web pages by integrating server-side data with HTML
templates.

Session and Cookies

 Session: A session stores data on the server for a specific user and is used to maintain state
across multiple requests. Sessions are temporary and expire when the user closes the browser or
logs out.

// Example using express-session


const session = require('express-session');
app.use(session({ secret: 'secret-key', resave: false, saveUninitialized:
true }));

 Cookies: Cookies are small text files stored on the user’s computer by the web browser. They can
persist across multiple sessions and are used to store user preferences, login information, and
other data.

// Example setting a cookie


res.cookie('username', 'JohnDoe', { maxAge: 900000, httpOnly: true });

Differences:

 Storage: Sessions are stored on the server, while cookies are stored on the client-side.
 Security: Sessions are generally more secure as they are stored on the server.
 Persistence: Cookies can persist across multiple sessions, while sessions expire when the browser
is closed.

 5. HTTP and Middleware

HTTP vs. HTTPS

o HTTP (Hypertext Transfer Protocol): Used for transferring data over the web. Data sent
via HTTP is not encrypted, making it vulnerable to interception.
o HTTPS (Hypertext Transfer Protocol Secure): Similar to HTTP but uses encryption
(SSL/TLS) to secure data transfer, protecting it from eavesdropping and tampering.
HTTP Methods (GET, POST, PUT, PATCH, DELETE, OPTIONS)

o GET: Retrieves data from the server.


o POST: Sends data to the server to create a new resource.
o PUT: Updates an existing resource with new data.
o PATCH: Partially updates an existing resource.
o DELETE: Removes a resource from the server.
o OPTIONS: Describes the communication options for the target resource.

Request and Response Headers

o Request Headers: Sent by the client to provide information about the request or the client
itself (e.g., Content-Type, Authorization).
o Response Headers: Sent by the server to provide information about the response
(e.g., Content-Length, Set-Cookie).

Status Codes (including 400 range)

o 200-299: Success (e.g., 200 OK, 201 Created).


o 300-399: Redirection (e.g., 301 Moved Permanently, 302 Found).
o 400-499: Client errors (e.g., 400 Bad Request, 401 Unauthorized, 404 Not Found).
o 500-599: Server errors (e.g., 500 Internal Server Error, 503 Service Unavailable).

CORS (Cross-Origin Resource Sharing)

CORS is a mechanism that allows a server to specify which origins (domains) can access its
resources. It uses HTTP headers to manage cross-origin requests and includes a preflight
request to check permissions.

res.send vs res.write vs res.end

 res.send: Sends a response to the client and ends the response process.

res.send('Hello, World!');

 res.write: Writes data to the response stream without ending it.

res.write('Hello, ');
res.write('World!');
res.end();

 res.end: Ends the response process. Can optionally send data before ending.

res.end('Goodbye!');
res.redirect

res.redirect sends a redirect response to the client, instructing it to navigate to a different


URL.
res.redirect('/new-url');

Handling Query Params and Path Params

 Query Parameters: Passed in the URL after the ? symbol and accessed via req.query.

// URL: /search?term=javascript
app.get('/search', (req, res) => {
const term = req.query.term;
res.send(`Search term: ${term}`);
});

 Path Parameters: Part of the URL path and accessed via req.params.

// URL: /users/123
app.get('/users/:id', (req, res) => {
const userId = req.params.id;
res.send(`User ID: ${userId}`);
});

HTTP OPTIONS Method and Preflight Requests

The OPTIONS method is used to describe the communication options for the target resource.
Preflight requests are sent by browsers to check if the server allows the actual request method
(like POST or DELETE) from a different origin.

app.options('/resource', (req, res) => {


res.set('Allow', 'GET,POST,OPTIONS');
res.send();
});

File Response and Download File

 Sending a File: Use res.sendFile to send a file to the client.

res.sendFile('/path/to/file');

 Downloading a File: Use res.download to prompt the client to download a file.

res.download('/path/to/file');
Middleware Types (Application, Router, Error-Handling)

 Application-Level Middleware: Applies to all routes in the app.

app.use((req, res, next) => {


console.log('Time:', Date.now());
next();
});

 Router-Level Middleware: Applies to specific routes defined in a router.

const router = express.Router();


router.use((req, res, next) => {
console.log('Request URL:', req.originalUrl);
next();
});
app.use('/api', router);

 Error-Handling Middleware: Handles errors in the app.

app.use((err, req, res, next) => {


console.error(err.stack);
res.status(500).send('Something broke!');
});

6. Streams, Events, and Asynchronous Operations

Streams (Readable, Writable, Duplex, Transform)


Streams are a way to handle reading/writing files or data in chunks, rather than all at once, which
is efficient for large amounts of data.
 Readable Streams: Used to read data from a source.

const fs = require('fs');
const readableStream = fs.createReadStream('file.txt');
readableStream.on('data', (chunk) => {
console.log(chunk);
});

 Writable Streams: Used to write data to a destination.

const writableStream = fs.createWriteStream('output.txt');


writableStream.write('Hello, World!');

 Duplex Streams: Both readable and writable.

const { Duplex } = require('stream');


const duplexStream = new Duplex({
read(size) {
this.push('Hello');
this.push(null);
},
write(chunk, encoding, callback) {
console.log(chunk.toString());
callback();
}
});

 Transform Streams: A type of duplex stream that can modify the data as it is read or written.

const { Transform } = require('stream');


const transformStream = new Transform({
transform(chunk, encoding, callback) {
this.push(chunk.toString().toUpperCase());
callback();
}
});

Stream Piping
Stream piping allows you to connect multiple streams together, passing data from one stream to
another.

const fs = require('fs');
const readableStream = fs.createReadStream('input.txt');
const writableStream = fs.createWriteStream('output.txt');
readableStream.pipe(writableStream);

Event-Driven Architecture
Event-driven architecture (EDA) is a design pattern where systems react to events. An event is a
significant change in state, like a user clicking a button. EDA allows systems to be more
responsive and scalable.

Event Emitter and Handlers

In Node.js, the EventEmitter class allows you to create, emit, and handle events.

const EventEmitter = require('events');


const eventEmitter = new EventEmitter();

// Event handler
eventEmitter.on('greet', (name) => {
console.log(`Hello, ${name}!`);
});
// Emit event
eventEmitter.emit('greet', 'Alice');

Asynchronous Operations (Callbacks, Promises)


Asynchronous operations allow your code to run without blocking other operations.
 Callbacks: Functions passed as arguments to be executed later.

function fetchData(callback) {
setTimeout(() => {
callback('Data fetched');
}, 1000);
}
fetchData((data) => {
console.log(data);
});

 Promises: Objects representing the eventual completion or failure of an asynchronous operation.

const promise = new Promise((resolve, reject) => {


setTimeout(() => {
resolve('Data fetched');
}, 1000);
});
promise.then((data) => {
console.log(data);
});

Promises and Promise Chaining


Promise chaining allows you to perform multiple asynchronous operations in sequence.

fetchData()
.then((data) => {
console.log(data);
return processData(data);
})
.then((processedData) => {
console.log(processedData);
})
.catch((error) => {
console.error(error);
});
Promisify
promisify converts callback-based functions to return promises.

const { promisify } = require('util');


const fs = require('fs');
const readFile = promisify(fs.readFile);

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

Callbacks
Callbacks are functions passed as arguments to other functions to be executed later.

function doSomething(callback) {
setTimeout(() => {
callback('Done');
}, 1000);
}
doSomething((message) => {
console.log(message);
});
.

async/await

async/await is a syntax for writing asynchronous code that looks synchronous.

async function fetchData() {


const data = await fetch('https://api.example.com/data');
const json = await data.json();
console.log(json);
}
fetchData();
7. Advanced Express.js

PUT vs. PATCH HTTP Methods (Idempotency)

 PUT: Used to update a resource. It is idempotent, meaning multiple identical requests will have
the same effect as a single request. It typically replaces the entire resource.

// Example: Updating a user


app.put('/user/:id', (req, res) => {
// Replace the entire user object
res.send('User updated');
});

 PATCH: Used for partial updates to a resource. It is not necessarily idempotent, meaning multiple
identical requests might have different effects.

// Example: Partially updating a user


app.patch('/user/:id', (req, res) => {
// Update parts of the user object
res.send('User partially updated');
});

Handling Scope Chaining (let vs. var)

 var: Function-scoped. Variables declared with var are accessible within the entire function.

function example() {
var x = 10;
if (true) {
var x = 20; // Same variable
console.log(x); // 20
}
console.log(x); // 20
}

 let: Block-scoped. Variables declared with let are only accessible within the nearest enclosing
block.

function example() {
let x = 10;
if (true) {
let x = 20; // Different variable
console.log(x); // 20
}
console.log(x); // 10
}

URL Encoding

URL encoding converts characters into a format that can be transmitted over the Internet. It
replaces unsafe ASCII characters with a % followed by two hexadecimal digits.

const encoded = encodeURIComponent('Hello World!'); // "Hello%20World%21"

Body-Parser vs. express.json and express.urlencoded

 body-parser: Middleware to parse incoming request bodies. It was commonly used before
Express 4.16.0.
 express.json(): Built-in middleware to parse JSON payloads.

app.use(express.json());

 express.urlencoded(): Built-in middleware to parse URL-encoded payloads.

app.use(express.urlencoded({ extended: true }));

Handling Cookies and Sessions

 Cookies: Small text files stored on the client-side. They can persist across sessions.

res.cookie('name', 'value', { maxAge: 900000, httpOnly: true });

 Sessions: Store data on the server-side and are used to maintain state across multiple requests.

const session = require('express-session');


app.use(session({ secret: 'secret-key', resave: false, saveUninitialized:
true }));

File Handling Using fs Module (readFile vs. readFileSync)

 readFile: Asynchronously reads the contents of a file.

const fs = require('fs');
fs.readFile('file.txt', 'utf8', (err, data) => {
if (err) throw err;
console.log(data);
});
 readFileSync: Synchronously reads the contents of a file.

const data = fs.readFileSync('file.txt', 'utf8');


console.log(data);

Reading and Writing to Files Asynchronously

 Reading a file asynchronously:

fs.readFile('file.txt', 'utf8', (err, data) => {


if (err) throw err;
console.log(data);
});

 Writing to a file asynchronously:

fs.writeFile('file.txt', 'Hello, World!', (err) => {


if (err) throw err;
console.log('File has been saved!');
});

8. Concurrency, Multithreading, and Child Processes

Node Concurrency Model


Node.js uses an event-driven, non-blocking I/O model. This means it can handle multiple
operations concurrently without waiting for any single operation to complete. It achieves this
through:

 Event Loop: Manages asynchronous operations.


 Callbacks: Functions executed after an asynchronous operation completes.
 Promises and async/await: Modern ways to handle asynchronous code.

Fork, Spawn, Exec, and ExecFile Methods

These methods from the child_process module allow you to create and manage child
processes:

 fork(): Creates a new Node.js process. Useful for running multiple instances of a Node.js
application.

const { fork } = require('child_process');


const child = fork('child.js');
 spawn(): Launches a new process with a given command. Provides more control over the
process’s input/output.

const { spawn } = require('child_process');


const ls = spawn('ls', ['-lh', '/usr']);

 exec(): Executes a command in a shell and buffers the output.

const { exec } = require('child_process');


exec('ls -lh', (error, stdout, stderr) => {
if (error) {
console.error(`exec error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});

 execFile(): Similar to exec(), but directly executes a file without a shell.

const { execFile } = require('child_process');


execFile('node', ['--version'], (error, stdout, stderr) => {
if (error) {
console.error(`execFile error: ${error}`);
return;
}
console.log(`stdout: ${stdout}`);
console.error(`stderr: ${stderr}`);
});

Child Processes

A child process is a process created by another process (the parent process). In Node.js, child
processes can be used to run multiple tasks concurrently, improving performance and scalability.

Clustering in Node.js

Clustering allows a Node.js application to take advantage of multi-core systems by creating


multiple instances (workers) of the application. Each worker runs on a separate CPU core,
distributing the load and improving performance.

const cluster = require('cluster');


const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello, world!');
}).listen(8000);
}

process.nextTick vs setImmediate

 process.nextTick(): Executes code after the current operation completes, before I/O tasks.

process.nextTick(() => {
console.log('Next tick');
});

 setImmediate(): Executes code after the current event loop phase, following I/O tasks.

setImmediate(() => {
console.log('Immediate');
});

PM2 Process Manager


PM2 is a process manager for Node.js applications. It helps manage and monitor applications,
providing features like load balancing, process management, and automatic restarts.

# Install PM2
npm install pm2 -g

# Start an application
pm2 start app.js

# Monitor applications
pm2 monit

REPL (Read-Eval-Print Loop)


The REPL is an interactive shell that allows you to execute JavaScript code and see the results
immediately. It’s useful for testing and debugging.

# Start REPL
node

# Example commands
> 2 + 2
4
> console.log('Hello, world!')
Hello, world!

Using Events and Child Processes Effectively

 Events: Use the EventEmitter class to handle events in your application.

const EventEmitter = require('events');


const emitter = new EventEmitter();

emitter.on('event', () => {
console.log('An event occurred!');
});

emitter.emit('event');

 Child Processes: Use child processes to run tasks concurrently, improving performance.

const { fork } = require('child_process');


const child = fork('child.js');

child.on('message', (message) => {


console.log(`Received message: ${message}`);
});

child.send('Hello, child process!');

9. Sockets and Security

WebSocket Communication in Node.js


WebSockets provide a way to open a persistent connection between the client and server,
allowing for real-time, bidirectional communication. This is useful for applications like chat apps,
live updates, and gaming.

Example using the ws library:

const WebSocket = require('ws');


const server = new WebSocket.Server({ port: 8080 });

server.on('connection', (socket) => {


socket.on('message', (message) => {
console.log(`Received: ${message}`);
socket.send(`Echo: ${message}`);
});
});
Socket.io for Real-Time Communication
Socket.io is a library that simplifies WebSocket communication and provides additional features
like automatic reconnection and fallback to HTTP long-polling if WebSockets are not supported.

Example:

const io = require('socket.io')(3000);

io.on('connection', (socket) => {


console.log('A user connected');
socket.on('message', (msg) => {
io.emit('message', msg);
});
});

Security Best Practices in Node.js

1. Use HTTPS: Encrypt data in transit.


2. Validate User Input: Prevent SQL injection and XSS attacks.
3. Use Environment Variables: Store sensitive information securely.
4. Limit Request Size: Prevent denial-of-service (DoS) attacks.
5. Regularly Update Dependencies: Keep your packages up-to-date to avoid vulnerabilities.

Authentication and Authorization (e.g., Passport.js)


Passport.js is a middleware for authentication in Node.js applications. It supports various
strategies like local (username/password), OAuth (Google, Facebook), and more.

Example:

const passport = require('passport');


const LocalStrategy = require('passport-local').Strategy;

passport.use(new LocalStrategy((username, password, done) => {


// Verify username and password
User.findOne({ username }, (err, user) => {
if (err) return done(err);
if (!user || !user.verifyPassword(password)) return done(null, false);
return done(null, user);
});
}));

CSRF Protection
Cross-Site Request Forgery (CSRF) attacks trick users into performing actions they didn’t
intend. To protect against CSRF, use tokens that are unique to each session and validate them on
the server.
Example using csurf middleware:

const csurf = require('csurf');


app.use(csurf());

app.post('/process', (req, res) => {


res.send('CSRF token is valid');
});

Encryption vs. Hashing (bcrypt, crypto)

 Encryption: Converts data into a format that can be reversed with a key. Used for data in transit
and storage.

const crypto = require('crypto');


const cipher = crypto.createCipher('aes-256-cbc', 'key');
let encrypted = cipher.update('data', 'utf8', 'hex');
encrypted += cipher.final('hex');

 Hashing: Converts data into a fixed-size string of characters, which cannot be reversed. Used for
storing passwords.

const bcrypt = require('bcrypt');


const hash = bcrypt.hashSync('password', 10);

Content Security Policy (CSP)


CSP is a security feature that helps prevent XSS attacks by specifying which sources of content
are allowed to be loaded on a web page.

Example:

<meta http-equiv="Content-Security-Policy" content="default-src 'self';


script-src 'self' https://trusted.com">

10. Configuration and Environment

Environment Variables and dotenv


Environment variables are dynamic values that can affect the way running processes behave on
a computer. They are often used to store configuration settings and sensitive information like API
keys, database credentials, etc.
dotenv is a popular Node.js package that loads environment variables from a .env file
into process.env. This helps keep sensitive information out of your codebase.
// Install dotenv
npm install dotenv

// Create a .env file


// .env
DB_HOST=localhost
DB_USER=root
DB_PASS=s1mpl3

// Load environment variables in your app


require('dotenv').config();
console.log(process.env.DB_HOST); // Output: localhost

Process Management and Cron Jobs


Process management involves managing the lifecycle of processes (starting, stopping,
monitoring). Tools like PM2 are often used for this in Node.js applications.

Cron jobs are scheduled tasks that run at specific intervals. They are useful for automating
repetitive tasks like backups, sending emails, etc.
# Example of a cron job that runs every day at midnight
0 0 * * * /path/to/your/script.sh

NVM (Node Version Manager)


NVM is a tool that allows you to manage multiple versions of Node.js on your machine. It makes
it easy to switch between different versions for different projects.
# Install NVM
curl -o- https://raw.githubusercontent.com/nvm-sh/nvm/v0.40.0/install.sh |
bash

# Install a specific Node.js version


nvm install 14

# Use a specific Node.js version


nvm use 14

Practical Examples

 Parsing hostname using URL module:

const url = new URL('https://example.com/path/name?query=string');


console.log(url.hostname); // Output: example.com

 Writing to a file with time:

const fs = require('fs');
const date = new Date().toISOString();
fs.writeFile('log.txt', `Log entry at ${date}\n`, { flag: 'a' }, (err) => {
if (err) throw err;
console.log('Log saved!');
});

Domain and Port Handling in Node.js


In Node.js, you can handle domains and ports using the http or https modules. You can also
manage virtual domains using libraries like vhost.

const http = require('http');

const server = http.createServer((req, res) => {


res.writeHead(200, { 'Content-Type': 'text/plain' });
res.end('Hello, world!\n');
});

server.listen(3000, '127.0.0.1', () => {


console.log('Server running at http://127.0.0.1:3000/');
});

11. Other Relevant Concepts

JSON Parsing and Stringifying

 Parsing: Converts a JSON string into a JavaScript object.

const jsonString = '{"name": "Alice", "age": 25}';


const obj = JSON.parse(jsonString);
console.log(obj.name); // Output: Alice

 Stringifying: Converts a JavaScript object into a JSON string.

const obj = { name: "Alice", age: 25 };


const jsonString = JSON.stringify(obj);
console.log(jsonString); // Output: {"name":"Alice","age":25}

Blocking vs Non-Blocking Code

 Blocking Code: Operations that block further execution until they complete. Example: reading a
file synchronously.

const fs = require('fs');
const data = fs.readFileSync('file.txt', 'utf8'); // Blocks here until file
is read
console.log(data);
 Non-Blocking Code: Operations that allow the program to continue executing while they
complete. Example: reading a file asynchronously.

fs.readFile('file.txt', 'utf8', (err, data) => {


if (err) throw err;
console.log(data);
});
console.log('This will run before the file is read');

Conditional Operator vs Optional Chaining

 Conditional Operator: A shorthand for if-else statements.

const age = 18;


const canVote = age >= 18 ? 'Yes' : 'No';
console.log(canVote); // Output: Yes

 Optional Chaining: Safely accesses deeply nested properties without causing errors if a property
is undefined or null.

const user = { name: "Alice", address: { city: "Wonderland" } };


console.log(user.address?.city); // Output: Wonderland
console.log(user.contact?.phone); // Output: undefined

Why Node.js Uses a Single Thread


Node.js uses a single-threaded event loop to handle multiple concurrent operations efficiently.
This design avoids the complexity of multi-threading and leverages asynchronous I/O operations
to handle many connections simultaneously without blocking the main thread.

Understanding the Thread Pool and Async Operations

 Thread Pool: Node.js uses a thread pool (via libuv) to handle tasks that cannot be performed
asynchronously by the event loop, such as file system operations.
 Async Operations: These operations run in the background, allowing the main thread to
continue executing other tasks. Callbacks, promises, and async/await are used to handle the
results of these operations.

Trace and Performance Tuning in Node.js

 Trace: Tools like node --trace-events and node --inspect help trace and debug
performance issues.
 Performance Tuning: Techniques include profiling your application, optimizing code, using
efficient algorithms, and monitoring resource usage to identify bottlenecks.

Binary JSON (BSON)


BSON (Binary JSON) is a binary representation of JSON-like documents. It is used by MongoDB
to store data more efficiently and support additional data types not available in JSON, such as
dates and binary data.

Using Middleware Effectively in Large Applications

 Organize Middleware: Group related middleware functions and use express.Router() to


modularize your application.
 Order Matters: Middleware is executed in the order it is defined. Place error-handling
middleware last.
 Reuse Middleware: Create reusable middleware functions for common tasks like authentication,
logging, and validation.

Custom Middleware Example


Here’s an example of custom middleware that logs the request method and URL:

const express = require('express');


const app = express();

// Custom middleware
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next(); // Pass control to the next middleware
};

app.use(logger);

app.get('/', (req, res) => {


res.send('Hello, World!');
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

12. Request and Response Lifecycle

Lifecycle of an HTTP Request and Response

Client Sends Request: A client (like a web browser) sends an HTTP request to a server. This request
includes a method (GET, POST, etc.), a URL, headers, and sometimes a body.
Server Processes Request: The server receives the request, processes it, and determines the
appropriate response.

Server Sends Response: The server sends back an HTTP response, which includes a status code
(e.g., 200 OK), headers, and sometimes a body (like HTML content).

Client Receives Response: The client receives the response and processes it, displaying the
content to the user or performing other actions.

Understanding Cookies and Sessions

 Cookies: Small text files stored on the client’s device. They can persist across sessions and are
used to store user preferences, session tokens, etc.

// Setting a cookie
res.cookie('name', 'value', { maxAge: 900000, httpOnly: true });

 Sessions: Store data on the server side and use a session ID stored in a cookie to track the user.
Sessions are more secure as the data is not stored on the client.

const session = require('express-session');


app.use(session({ secret: 'secret-key', resave: false, saveUninitialized:
true }));

Changing Status Codes of a Response


You can change the status code of an HTTP response to indicate the result of the request.

// Setting a status code


res.status(404).send('Not Found');

Common status codes include:

 200 OK: Request succeeded.


 404 Not Found: Resource not found.
 500 Internal Server Error: Server encountered an error.

Handling Login and Redirection


To handle login and redirection, you can check if a user is logged in and redirect them
accordingly.
JavaScript
app.get('/login', (req, res) => {
if (req.session.user) {
res.redirect('/dashboard');
} else {
res.send('Login Page');
}
});
 301 Moved Permanently: Permanent redirection.
 302 Found: Temporary redirection.

Path and URL Handling

 URL Fragments: Part of a URL that follows a # symbol. Used to navigate to a specific section of a
page.

const url = new URL('https://example.com/path#section');


console.log(url.hash); // Output: #section

HTTP Request Payloads

 GET Requests: Typically, GET requests do not have a body. They are used to retrieve data.
 POST Requests: Used to send data to the server.

// Example of a POST request with a body


fetch('/api/data', {
method: 'POST',
headers: { 'Content-Type': 'application/json' },
body: JSON.stringify({ key: 'value' })
});

13. Performance and Debugging

Debugging Node.js Applications


Debugging helps you find and fix errors in your code. Here are some common methods:

 Using console.log(): Simple but effective for quick checks.


 Node.js Inspector: Start your app with node --inspect and use Chrome DevTools to debug.
 VS Code Debugger: Set breakpoints and step through your code using Visual Studio Code.

Handling Large-Scale Applications with Node.js


To handle large-scale applications, consider these strategies:

 Microservices: Break your application into smaller, independent services.


 Load Balancing: Distribute incoming requests across multiple servers.
 Clustering: Use Node.js’s cluster module to utilize multiple CPU cores.

Using Event-Driven Programming Effectively


Event-driven programming allows your application to respond to events (like user actions or
messages from other programs). Key components include:

 Event Emitters: Objects that emit named events.


 Event Listeners: Functions that respond to those events.
const EventEmitter = require('events');
const emitter = new EventEmitter();

emitter.on('event', () => {
console.log('An event occurred!');
});

emitter.emit('event');

Performance Optimization Strategies

 Stream Usage: Use streams to handle large data efficiently.

const fs = require('fs');
const readStream = fs.createReadStream('largefile.txt');
readStream.on('data', (chunk) => {
console.log(`Received ${chunk.length} bytes of data.`);
});

 Clustering: Use the cluster module to run multiple instances of your application.

const cluster = require('cluster');


const http = require('http');
const numCPUs = require('os').cpus().length;

if (cluster.isMaster) {
for (let i = 0; i < numCPUs; i++) {
cluster.fork();
}
} else {
http.createServer((req, res) => {
res.writeHead(200);
res.end('Hello, world!');
}).listen(8000);
}

Profiling and Performance Tuning

 Profiling: Use tools like node --prof to analyze your application’s performance.
 Trace: Use the trace module to track function calls and execution times.

Monitoring Node.js Applications with PM2


PM2 is a process manager that helps you manage and monitor your Node.js applications.

 Start an application: pm2 start app.js


 Monitor applications: pm2 monit
 View logs: pm2 logs
Using the REPL for Quick Debugging and Experimentation
The REPL (Read-Eval-Print Loop) is an interactive shell that allows you to execute JavaScript code
and see the results immediately. It’s useful for testing and debugging.

# Start REPL
node

# Example commands
> 2 + 2
4
> console.log('Hello, world!')
Hello, world!

14. Final Review and Practice

Core Node.js Concepts

1. Event Loop: The mechanism that allows Node.js to perform non-blocking I/O operations. It
handles asynchronous operations by using callbacks, promises, and async/await.
2. Non-blocking I/O: Node.js uses non-blocking I/O to handle multiple operations concurrently
without waiting for each to complete.
3. CommonJS Module System: Node.js uses CommonJS for module management. You
use require to import modules and module.exports to export them.
4. Global Objects: Objects like process, global, and console are available globally in Node.js.

Practical Examples

 Scaffolding a New Project:


 mkdir my-node-app
 cd my-node-app
 npm init -y
 npm install express

 Creating Custom Middleware:

const express = require('express');


const app = express();

// Custom middleware
const logger = (req, res, next) => {
console.log(`${req.method} ${req.url}`);
next();
};

app.use(logger);
app.get('/', (req, res) => {
res.send('Hello, World!');
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

Review package.json Components and Dependencies

 package.json: This file contains metadata about your project and its dependencies.

{
"name": "my-node-app",
"version": "1.0.0",
"description": "A simple Node.js app",
"main": "index.js",
"scripts": {
"start": "node index.js"
},
"dependencies": {
"express": "^4.17.1"
},
"devDependencies": {
"nodemon": "^2.0.7"
}
}

Understanding and Practicing Middleware Usage

Middleware functions are functions that have access to the request object (req), the response
object (res), and the next middleware function in the application’s request-response cycle.

 Example:

app.use((req, res, next) => {


console.log('Time:', Date.now());
next();
});
Implementing Real-World Use Cases with Express.js

 Example: Creating a simple REST API.

const express = require('express');


const app = express();
app.use(express.json());

let items = [];

app.get('/items', (req, res) => {


res.json(items);
});

app.post('/items', (req, res) => {


const item = req.body;
items.push(item);
res.status(201).json(item);
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

Building a REST API from Scratch

1. Set up the project:


2. mkdir rest-api
3. cd rest-api
4. npm init -y
5. npm install express

Create the server:

const express = require('express');


const app = express();
app.use(express.json());

app.get('/', (req, res) => {


res.send('Welcome to the REST API');
});

app.listen(3000, () => {
console.log('Server is running on port 3000');
});
Handling Complex Routing Scenarios

 Example: Using Express Router for modular routing.

const express = require('express');


const app = express();
const router = express.Router();

router.get('/users', (req, res) => {


res.send('User list');
});

router.post('/users', (req, res) => {


res.send('Create user');
});

app.use('/api', router);

app.listen(3000, () => {
console.log('Server is running on port 3000');
});

Event Emitters and the Event Loop in Real-World Applications

 Event Emitters: Used to handle custom events.

const EventEmitter = require('events');


const emitter = new EventEmitter();

emitter.on('event', () => {
console.log('An event occurred!');
});

emitter.emit('event');

 Event Loop: Manages asynchronous operations.


setTimeout(() => {
console.log('This runs after 1 second');
}, 1000);

console.log('This runs first');

You might also like