Node Notes
Node Notes
Node Notes
js
Introduction:
Node.js is an open-source, cross-platform, server-side runtime environment built on
Chrome's V8 JavaScript engine. It enables developers to execute JavaScript code outside the
web browser, allowing them to build scalable, high-performance, and networked
applications. Node.js is well-known for its event-driven, non-blocking I/O model, making it
particularly suitable for real-time applications and high-traffic websites.
What is Node.js?
Node.js is a server-side technology that allows developers to run JavaScript code on the
server. Traditionally, JavaScript was mainly used for client-side scripting within web browsers,
but Node.js extends its capabilities to the server-side. This means developers can use the
same language and share code between the front-end and back-end, streamlining the
development process and improving code reusability.
Advantages of Node.js:
1. Asynchronous and Non-blocking: One of the most significant advantages of Node.js is its
asynchronous, non-blocking I/O model. It uses an event loop that allows it to handle
multiple concurrent connections efficiently without blocking the execution of other tasks.
This makes Node.js highly scalable and well-suited for real-time applications like chat
applications, online gaming, and streaming services.
2. Fast Execution: Node.js is built on the V8 engine, the same JavaScript engine used by
Google Chrome. V8 compiles JavaScript code directly into machine code, resulting in faster
execution times compared to traditional server-side technologies.
3. Single Language: With Node.js, both the client-side and server-side can be written in
JavaScript, promoting code sharing and improving development speed. Developers can use
the same language and libraries across different layers of the application.
4. Large Package Ecosystem: Node.js has a vast and vibrant ecosystem of open-source
packages available through the Node Package Manager (npm). These packages can be easily
integrated into applications, saving development time and effort.
5. Community and Support: Node.js has a large and active community of developers, making
it easy to find tutorials, guides, and solutions to common problems. The community actively
contributes to the improvement and expansion of the Node.js ecosystem.
6. Lightweight and Scalable: Node.js is lightweight and consumes minimal resources, making
it suitable for deploying on servers with limited memory and processing power. It also
supports horizontal scaling, allowing developers to add more servers to handle increased
traffic.
2. Scalability: Scaling traditional web servers can be challenging due to the thread-per-
connection model. Adding more threads can lead to increased resource consumption and
might not scale linearly with the number of connections.
3. Blocking I/O: Traditional web servers often use blocking I/O operations, which means a
thread waits for an operation to complete before moving on to the next task. This can result
in inefficient resource utilization, especially in scenarios where I/O operations take a
considerable amount of time.
The event-driven nature of Node.js allows it to efficiently handle I/O operations without
blocking the execution of other tasks. When an I/O operation, such as reading from a file or
making an HTTP request, is initiated, Node.js delegates the operation to the underlying
system and continues executing the rest of the code without waiting for the I/O to complete.
Asynchronous I/O operations are essential for handling concurrent connections and real-
time applications efficiently. It ensures that the server can continue processing other
requests while waiting for time-consuming operations, such as reading from a database or
sending data over the network.
3. Event Loop:
The event loop is the heart of the Node.js process model. It is responsible for handling
events, executing callbacks, and managing I/O operations. The event loop continuously
checks for pending events and executes their associated callbacks when appropriate.
The event loop keeps running as long as there are events to process. It is the single-threaded
nature of Node.js that ensures the event loop can handle multiple connections concurrently.
In conclusion, the Node.js process model's single-threaded, event-driven nature, along with
its support for asynchronous I/O operations, enables it to handle high concurrency and build
scalable applications efficiently. Developers can take advantage of this model to create
responsive and performant server-side applications in Node.js.
Setup Dev Environment
In this module, you will learn how to set up your development environment for Node.js
application development. We'll cover the installation process for Windows and macOS, and
we'll also explore working with the Node.js REPL (Read-Eval-Print Loop) and the Node.js
Console.
Node.js comes with a built-in interactive command-line interface called the REPL. The REPL
allows you to enter JavaScript expressions, statements, and code snippets interactively and
see their results immediately.
To start the Node.js REPL, open your Command Prompt or Terminal and type `node`:
$ node
After hitting Enter, you'll see the Node.js prompt (`>`), indicating that you are now in the
REPL. You can now type and execute JavaScript code directly in the REPL.
Example usage in the Node.js REPL:
> const message = "Hello, Node.js!";
undefined
> console.log(message);
Hello, Node.js!
undefined
>2+3
5
> const multiply = (a, b) => a * b;
undefined
> multiply(4, 5)
20
> .exit
```
To exit the REPL, type `.exit` and press Enter.
4. Node.js Console:
Node.js also provides a built-in global object called `console`, which allows you to interact
with the Node.js Console. The Node.js Console is used to print output, errors, and debugging
information during the execution of your Node.js applications.
To work with the Node.js Console, you can use the `console` object methods like
`console.log()`, `console.error()`, and `console.debug()`.
The Node.js Console is a valuable tool for understanding what's happening in your
application and can be helpful for debugging purposes.
With these steps and tools in place, you have set up your Node.js development environment
and can start building and running Node.js applications on your system. Happy coding!
Node.js Modules
In this module, you will learn about Node.js modules and how they enable modularity and
separation of concerns in your Node.js applications. We'll cover functions, buffers, and
different types of modules, including core modules and local modules. Additionally, we'll
explore the concept of `module.exports`, which is essential for exporting functionality from
one module to another.
1. Functions:
In JavaScript, functions are blocks of code that can be defined and invoked to perform
specific tasks. Functions are reusable and allow you to organize and structure your code in a
modular way. In Node.js, you can create functions like in any other JavaScript environment.
4. Module Types:
In Node.js, there are two main types of modules:
a. Core Modules: These are built-in modules that come bundled with Node.js. Examples
include `fs` (file system), `http` (HTTP server and client), `path` (file path utilities), etc.
b. Local Modules: These are modules created by developers to encapsulate specific
functionality in separate files. You can use local modules within your application by requiring
them.
5. Core Modules:
Node.js provides various core modules that you can use directly without the need for
installation or external dependencies. To use a core module, you need to import it using the
`require` function.
Example of using a core module (fs) in Node.js:
```
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
});
```
6. Local Modules:
Local modules are custom modules created by developers to encapsulate specific
functionality in separate files. To create a local module, you define the functionality in a
separate `.js` file and export it using the `module.exports` object.
7. `module.exports`:
The `module.exports` object is used to export functionality from a module. When you assign
properties or functions to `module.exports`, they become accessible to other modules that
require this module.
Example of using `module.exports` to export a function from a local module:
File: `greet.js`
```
module.exports = (name) => `Hello, ${name}!`;
```
File: `app.js`
```
const greet = require('./greet');
console.log(greet('John')); // Output: Hello, John!
```
In this module, you will learn about the Node Package Manager (NPM) and how to use it to
install, update, and manage packages in your Node.js projects. We'll cover installing
packages locally and globally, adding dependencies to your `package.json` file, and updating
packages.
1. What is NPM:
NPM is the default package manager for Node.js, and it comes bundled with Node.js
installation. It is a command-line tool that allows developers to discover, install, and manage
packages (libraries and tools) from the vast NPM registry. NPM also facilitates version
management, package dependencies, and other essential features for Node.js development.
Note: Global packages are installed in a system-wide directory and can be accessed from the
command-line directly. However, it's generally recommended to install packages locally in
your project directory, as global packages may cause version conflicts or inconsistencies
between projects.
5. Updating Packages:
NPM allows you to update packages to the latest versions using the `npm update` command.
This command will update all packages in your `node_modules` folder to the latest versions
that satisfy the version range specified in your `package.json` file.
Example of updating packages:
```
npm update
```
To update a specific package to the latest version, you can specify the package name:
```
npm update package-name
```
6. Updating Your Package to NPM:
If you have developed a Node.js package/module and want to share it with the community,
you can publish it to the NPM registry. To do this, you need to create an NPM account and
use the `npm publish` command.
After publishing your package, other developers can easily install it using `npm install
package-name`.
Remember that when publishing packages to NPM, it's essential to follow best practices and
ensure your package is well-documented and versioned correctly.
With NPM, you can easily manage dependencies, share your Node.js modules with others,
and keep your projects up-to-date with the latest packages, enhancing the productivity and
efficiency of your Node.js development workflow.
Creating Web Server
In this module, you will learn how to create a basic web server in Node.js. We will cover
handling GET, POST, PUT, and DELETE requests, listening on specific port numbers, and
handling routing for different HTTP methods.
To create a web server in Node.js, you need to use the built-in `http` module, which provides
the necessary functionality to handle HTTP requests and responses.
Example of creating a basic web server in Node.js:
```
const http = require('http');
// Create the server
const server = http.createServer((req, res) => {
// Set the response header
res.writeHead(200, { 'Content-Type': 'text/plain' });
// Write the response
res.write('Hello, this is a basic web server in Node.js!');
res.end();
});
// Listen on a specific port
const port = 3000;
server.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
```
2. Handling GET Requests:
To handle GET requests, you can check the `req.method` property in the request object and
respond accordingly.
Example of handling GET requests in the web server:
```
const http = require('http');
// ...
```
3. Handling POST Requests:
To handle POST requests, you need to read the incoming data from the request and respond
accordingly. This often involves parsing the request body.
Example of handling POST requests in the web server using the `data` and `end` events:
```js
const http = require('http');
const server = http.createServer((req, res) => {
if (req.method === 'POST') {
let data = '';
req.on('data', (chunk) => {
data += chunk;
});
req.on('end', () => {
res.writeHead(200, { 'Content-Type': 'text/plain' });
res.write(`This is a POST request. Data received: ${data}`);
res.end();
});
}
});
// ...
```
Similarly, you can handle PUT and DELETE requests by checking the `req.method` property
and implementing the desired functionality accordingly.
To handle different routes (URL paths) in your web server, you can use the `req.url` property
to determine the requested path and respond accordingly.
// ...
```
With these examples, you can create a basic web server in Node.js, handle various HTTP
requests, listen on specific port numbers, and implement routing for different URL paths.
This forms the foundation for building more complex web applications and RESTful APIs
using Node.js.
Handling HTTP Requests and Sending Requests in Node.js
In this section, we will cover how to handle incoming HTTP requests in a Node.js web server
and how to send HTTP requests to external servers or APIs.
To handle incoming HTTP requests in Node.js, you can use the `http` module to create a web
server, as shown in Module 5. When a request is made to your server, the server's callback
function will be executed, allowing you to read the request, process it, and send an
appropriate response.
// ...
```
Inside the callback function, you can access information about the incoming request using
properties of the `req` object, such as `req.method`, `req.url`, `req.headers`, etc.
To send an HTTP POST request, you need to set the `method` property to `'POST'` and
include the request body using the `req.write()` method.
Example of sending an HTTP POST request using the `http` module:
```
const http = require('http');
const options = {
hostname: 'api.example.com',
path: '/data',
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
};
const req = http.request(options, (res) => {
// Response handling code goes here
// ...
});
req.on('error', (error) => {
console.error(error);
});
const dataToSend = JSON.stringify({ key: 'value' });
req.write(dataToSend);
req.end();
```
In this example, we are sending an HTTP POST request with a JSON payload to the
`api.example.com/data` endpoint.
If you need to send requests to an external server using the HTTPS protocol, you can use the
`https` module, which is similar to the `http` module but works over SSL/TLS.
const options = {
hostname: 'api.example.com',
path: '/data',
method: 'GET',
};
req.end();
```
Remember to handle the response from the external server or API in the request callback,
and handle any errors that may occur during the request.
With these examples, you can handle incoming HTTP requests in your Node.js web server
and send HTTP requests to external servers or APIs to interact with other services and
retrieve or send data.
File System (fs) in Node.js
In this module, we will explore the File System module (`fs`) in Node.js, which provides
methods for working with files and directories. We'll cover reading, writing, updating files,
understanding the concept of chunks and buffers, and performing file-related operations
synchronously and asynchronously.
1. `fs.readFile`:
The `fs.readFile` method is used to read the contents of a file asynchronously. It takes the file
path and an optional encoding as arguments and returns the file's contents in the specified
encoding.
Example of using `fs.readFile` to read a file asynchronously:
```
const fs = require('fs');
fs.readFile('file.txt', 'utf-8', (err, data) => {
if (err) throw err;
console.log(data);
});
```
2. Writing a File:
The `fs.writeFile` method is used to write data to a file asynchronously. If the file does not
exist, it will be created; if it exists, its contents will be replaced.
Example of using `fs.writeFile` to write data to a file asynchronously:
```
const fs = require('fs');
const data = 'Hello, Node.js!';
fs.writeFile('file.txt', data, (err) => {
if (err) throw err;
console.log('File written successfully.');
});
```
3. Writing a File Asynchronously:
The `fs.writeFileSync` method is used to write data to a file synchronously. Unlike the
asynchronous version, this method will block the execution until the file operation is
complete.
Example of using `fs.writeFileSync` to write data to a file synchronously:
```
const fs = require('fs');
const data = 'Hello, Node.js!';
fs.writeFileSync('file.txt', data);
console.log('File written synchronously.');
```
4. Opening a File:
The `fs.open` method is used to open a file. It takes the file path, the file system flag (e.g., 'r'
for read), and a callback function. The callback function receives a file descriptor that can be
used for other file-related operations.
Example of using `fs.open` to open a file:
```
const fs = require('fs');
fs.open('file.txt', 'r', (err, fd) => {
if (err) throw err;
// Perform other file operations using the file descriptor (fd)
});
```
5. Deleting a File:
The `fs.unlink` method is used to delete a file asynchronously.
Example of using `fs.unlink` to delete a file asynchronously:
```
const fs = require('fs');
fs.unlink('file.txt', (err) => {
if (err) throw err;
console.log('File deleted successfully.');
});
```
6. Other I/O Operations:
Node.js `fs` module provides many other methods for file-related operations, such as
renaming files, appending data to files, creating directories, checking file existence, and
more.
Example of appending data to a file using `fs.appendFile`:
```
const fs = require('fs');
const dataToAppend = '\nAppended text.';
fs.appendFile('file.txt', dataToAppend, (err) => {
if (err) throw err;
console.log('Data appended to file successfully.');
});
```
These are some of the essential file system operations available in Node.js. Remember to
handle errors properly when working with file I/O, and consider using the asynchronous
versions of methods for better performance and scalability, especially in production
environments.
Debugging Node.js Applications
In this module, you will learn how to debug Node.js applications. Debugging is the process of
identifying and fixing bugs and performance issues in your code. We'll cover using the core
Node.js debugger and debugging with Visual Studio Code, a popular integrated development
environment (IDE) that provides powerful debugging capabilities for Node.js applications.
Node.js comes with a built-in debugging utility that allows you to debug your applications
directly from the command line. To enable debugging, you need to start your Node.js
application with the `--inspect` flag.
Example of starting a Node.js application in debug mode:
```bash
node --inspect index.js
```
Once your application is running in debug mode, you can connect to it using a debugger tool
like Chrome DevTools or any other inspector. Open Google Chrome and type
`chrome://inspect` in the address bar. You will see a list of available Node.js processes to
debug. Click on the "Inspect" link to open the developer tools and start debugging your
Node.js application.
Visual Studio Code (VS Code) is a popular code editor that provides excellent support for
Node.js development, including powerful debugging features. To debug a Node.js
application in VS Code, follow these steps:
Step 1: Install VS Code:
If you don't have Visual Studio Code installed, you can download it from the official website:
https://code.visualstudio.com/
Step 2: Install Node.js Extension:
In VS Code, click on the Extensions icon on the left sidebar, search for "Node.js" in the
marketplace, and install the official Node.js extension.
Step 3: Set Breakpoints:
Open your Node.js application file in VS Code and set breakpoints by clicking on the gutter
next to the line number where you want to pause the execution for debugging.
Using VS Code's debugging capabilities, you can efficiently identify and resolve issues in your
Node.js application, making the development process more efficient and productive.
Remember that debugging is a powerful tool, but it's essential to use it judiciously and only
when necessary. It's a valuable skill that can save you a lot of time and effort in the
development and optimization of your Node.js applications.
Events in Node.js
In this module, you will learn about events in Node.js and the significance of event-driven
programming. Node.js is built on an event-driven architecture, where certain objects
(EventEmitters) emit events when specific actions or conditions occur. We'll cover the
EventEmitter class, how to work with events, write custom events, and inherit events in
Node.js.
1. EventEmitter Class:
Node.js provides the built-in EventEmitter class that serves as the foundation for working
with events. It allows objects to emit named events and register listeners to handle those
events.
To work with events in Node.js, you need to create an instance of the EventEmitter class and
use its methods to emit events and register event listeners.
You can extend the EventEmitter class and create your own custom classes that can emit and
listen to events.
Example of returning an EventEmitter in a custom class:
```
const EventEmitter = require('events');
class MyCustomEmitter extends EventEmitter {
someMethod() {
// Do something...
this.emit('customEvent', 'Data from custom emitter');
}
}
const myCustomEmitter = new MyCustomEmitter();
myCustomEmitter.on('customEvent', (data) => {
console.log('Custom event data received:', data);
});
myCustomEmitter.someMethod();
```
3. Inheriting Events:
You can inherit events from one EventEmitter instance to another using the `eventNames()`,
`listeners()`, and other methods provided by the EventEmitter class.
Example of inheriting events from one EventEmitter to another:
```
const EventEmitter = require('events');
class MyCustomEmitter extends EventEmitter {
// ... custom methods and logic ...
}
const myEmitter = new EventEmitter();
const myCustomEmitter = new MyCustomEmitter();
// Inherit events from myEmitter to myCustomEmitter
const eventNames = myEmitter.eventNames();
eventNames.forEach((eventName) => {
const listeners = myEmitter.listeners(eventName);
listeners.forEach((listener) => {
myCustomEmitter.on(eventName, listener);
});
});
// Emit an event from myEmitter
myEmitter.emit('customEvent', 'Data from myEmitter');
// myCustomEmitter will also receive and handle the 'customEvent' event
```
In Node.js, events play a crucial role in creating responsive and scalable applications. By
using the EventEmitter class and event-driven programming, you can handle asynchronous
operations efficiently, making Node.js well-suited for building real-time applications, servers,
and more. Understanding events is fundamental to becoming proficient in Node.js
development.
Express.js
In this module, you will learn how to use Express.js, one of the most popular frameworks for
building web applications in Node.js. Express.js provides a simple and efficient way to handle
routing, middleware, and other web application-related tasks, allowing you to create web
applications with minimal code.
1. Configuring Routes:
In Express.js, routes are used to define the paths and corresponding handlers for different
HTTP methods (GET, POST, PUT, DELETE, etc.). Routes are essential for defining the behavior
of your web application based on the incoming requests.
Example of configuring routes in Express.js:
```
const express = require('express');
const app = express();
// Define a route for the home page
app.get('/', (req, res) => {
res.send('Welcome to the home page!');
});
// Define a route for the about page
app.get('/about', (req, res) => {
res.send('This is the about page.');
});
// Define a route for handling POST requests
app.post('/api/data', (req, res) => {
// Handle the POST request and send a response
});
// ... other routes ...
// Start the server
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
```
2. Working with Express:
Express.js simplifies the process of creating web applications in Node.js by providing a robust
set of features, including middleware support, routing, template engines, and more. You can
use various middleware functions and third-party modules to enhance the functionality of
your application.
Example of using middleware in Express.js:
```
const express = require('express');
const app = express();
// Custom middleware to log request information
const logger = (req, res, next) => {
console.log(`Received ${req.method} request for ${req.url}`);
next();
};
// Use the custom middleware for all routes
app.use(logger);
// Define routes
// ...
// Start the server
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
```
In this example, we've created a custom middleware function called `logger` to log
information about incoming requests. We then use the `app.use()` method to apply the
`logger` middleware to all routes.
Express.js allows you to easily integrate with other modules and databases, making it a
versatile framework for building web applications, RESTful APIs, and more.
By leveraging Express.js, you can create efficient and scalable web applications with
minimum coding, making it a popular choice among Node.js developers. Understanding
Express.js and its features is essential for building robust and modern web applications in
the Node.js ecosystem.
Serving Static Resources in Express.js
In this module, you will learn how to serve static resources, such as HTML pages, CSS files,
images, and other assets, to the browser using Express.js. Express.js provides built-in
middleware functions to serve static files efficiently.
To serve static files in Express.js, you can use the built-in `express.static` middleware
function. This function takes the path to the directory containing your static resources as an
argument and serves them automatically.
Example of serving static files in Express.js:
```
const express = require('express');
const app = express();
// Serve static files from the "public" directory
app.use(express.static('public'));
// Define other routes and middleware as needed
// ...
// Start the server
const port = 3000;
app.listen(port, () => {
console.log(`Server is running on port ${port}`);
});
```
In this example, all the files in the "public" directory, such as HTML, CSS, images, etc., will be
served automatically by Express.js.
2. Working with Middleware:
In this example, we've added two custom middleware functions: `logger` and
`addCustomHeader`. The `logger` function logs information about incoming requests, while
the `addCustomHeader` function adds a custom header to the response. We use the
`app.use()` method to apply these middleware functions to all routes.
Middleware allows you to modularize your application's logic and add cross-cutting concerns
without duplicating code. It's a powerful feature of Express.js that contributes to its
flexibility and extensibility.
By serving static resources and using middleware effectively, you can enhance the
performance and functionality of your Express.js web applications, making them more user-
friendly and efficient.
Database Connectivity in Node.js
In this module, you will learn how to connect to a SQL Server database in Node.js and
perform CRUD (Create, Read, Update, Delete) operations. We will use different Node.js
modules to establish the database connection and interact with the database.
1. Connection String:
To connect to a SQL Server database, you need to provide a connection string, which
contains information about the database server, credentials, and other settings required for
the connection.
To configure the database connection, you can use a Node.js module like `mssql`, which
provides an easy-to-use API for working with SQL Server databases.
Example of configuring the database connection with `mssql`:
```
const sql = require('mssql');
const config = {
server: 'localhost',
database: 'mydatabase',
user: 'myuser',
password: 'mypassword',
options: {
trustedConnection: true,
encrypt: true,
}
};
// Create a pool of connections
const pool = new sql.ConnectionPool(config);
const poolConnect = pool.connect();
poolConnect.then(() => {
console.log('Connected to the database.');
}).catch((err) => {
console.error('Error connecting to the database:', err);
});
```
3. Working with Select Command:
To execute a SELECT query and retrieve data from the database, you can use the `request`
method of the connection pool.
In this module, you will learn about template engines in Node.js and how to use them to
perform two-way data binding and dynamically render dynamic data on webpages. We will
explore different view engines and their syntax for generating HTML content dynamically.
Template engines simplify the process of rendering HTML pages with dynamic content,
making it easy to create reusable templates and manage view logic efficiently.
3. What is Vash:
Vash is another template engine for Node.js that is inspired by Razor syntax from ASP.NET. It
provides a simple and familiar syntax for generating HTML content.