node js for engineering students
node js for engineering students
Features of JavaScript
o Client-side validation,
o Dynamic drop-down menus,
o Displaying date and time,
o Displaying pop-up windows and dialog boxes (like an alert dialog box,
confirm dialog box and prompt dialog box),
o Displaying clocks etc.
JavaScript Example
<script>
document.write("Hello JavaScript by JavaScript");
</script>
Key Concepts:
Concepts
The following diagram depicts some important parts of Node.js which we will
discuss in detail in the subsequent chapters.
Examples:
var http = require('http');
http.createServer(function (req, res) {
res.writeHead(200, {'Content-Type': 'text/plain'});
res.end('Hello World!');
}).listen(8080);
1.3 Asynchronous Programming in Node.js
Asynchronous programming is a programming paradigm that allows tasks
to run independently of each other, improving performance and
responsiveness in applications.
In Node.js, asynchronous programming is essential due to its single-
threaded, event-driven architecture.
By leveraging asynchronous techniques, developers can ensure that their
applications remain responsive and can handle multiple requests
concurrently.
npm i async
****NPM (Node Package Manager) is the default package manager for Node and is written
entirely in JavaScript.
Promises
Promises provide a more structured way to handle asynchronous
operations in Node.js.
A promise represents the eventual completion or failure of an
asynchronous operation and allows chaining multiple asynchronous
operations together. Promises improve code readability and make error
handling easier.
Async/Await
Introduced in ES2017, async/await is a modern approach to writing
asynchronous code in a more synchronous style.
By using the async keyword to define an asynchronous function
and await to wait for promises to resolve, developers can write code that
resembles synchronous programming while leveraging the benefits of
synchronicity.
// Using async/await
async function executeAsyncTask() {
try {
const result = await simulateAsyncTask();
console.log(result); // Task completed successfully!
} catch (error) {
console.error(error); // Task failed!
}
}
// Calling the async function
executeAsyncTask();
Error handling is crucial when working with asynchronous code to ensure the
stability and reliability of applications. Different techniques are used depending
on the chosen asynchronous pattern.
Error-First Callbacks
When using async/await, error handling can be done using traditional try/catch
blocks. This allows developers to catch and handle errors within the same scope
as synchronous code, making error handling more intuitive.
Callback Hell refers to the situation where callbacks are nested within each
other, leading to code that is difficult to read and maintain. To avoid this,
developers can use techniques such as modularization, promises, or async/await
to flatten the code and make it more manageable.
Promises and async/await provide more structured and readable ways to handle
asynchronous code. Whenever possible, prefer using promises or async/await
over raw callbacks to improve code clarity and maintainability.
Example
setTimeout(function(){
}, 1000);
output
When Node.js starts, it initializes the event loop, processes the provided
input script which may make async API calls, schedules timers, then
begins processing the event loop.
In the previous example, the initial input script consisted of
console.log() statements and a setTimeout() function which schedules a
timer.
When using Node.js, a special library module called libuv is used to
perform async operations. This library is also used, together with the
back logic of Node, to manage a special thread pool called the libuv
thread pool.
This thread pool is composed of four threads used to delegate operations
that are too heavy for the event loop.
I/O operations, Opening and closing connections, setTimeouts are
examples of such operations.
When the thread pool completes a task, a callback function is called
which handles the error(if any) or does some other operation.
This callback function is sent to the event queue.
When the call stack is empty, the event goes through the event queue
and sends the callback to the call stack.
The following diagram is a proper representation of the event loop in a
Node.js server:
console.log('Start');
setTimeout(() => {
console.log('Timeout callback');
}, 2000);
console.log('End');
In this example, the setTimeout() function is called with a callback that will
print “Timeout callback” to the console after 2000 milliseconds (2 seconds).
This function is added to the message queue in the timers phase, and the event
loop will process it after the synchronous code is executed. The output will be:
Start
End
Timeout callback
As you can see, the “Timeout callback” is printed after 2 seconds, after the
“Start” and “End” are printed, because the setTimeout() function is non-
blocking and its callback is processed by the event loop after the execution of
the synchronous code.
2. Pending Callbacks: This phase processes any callbacks that have been
added to the message queue by asynchronous functions.
Here is an example of how the pending callbacks phase works:
console.log('Start');
setImmediate(() => {
console.log('Immediate callback');
});
console.log('End');
In this example, the setImmediate() function is called with a callback that will
print “Immediate callback” to the console. This function is added to the
message queue in the pending callbacks phase, and the event loop will process
it after the timers phase. The output will be:
Start
End
Immediate callback
3. Idle, Prepare: The “idle.ignore” phase is not a standard phase of the event
loop in Node.js. It means it’s Used internally only. The “idle” phase is a period
of time during which the event loop has nothing to do and can be used to
perform background tasks, such as running garbage collection or checking for
low-priority events.
“idle.ignore” is not an official phase of the event loop, it is a way to ignore the
idle phase, meaning that it will not use the time of the idle phase to perform
background tasks.
An example of using idle.ignore can be:
Here we are using the idle-gc package, which allows you to ignore the idle
phase. This can be useful in situations where you want to ensure that the event
loop is always busy and that background tasks are not performed.
It’s worth mentioning that, in general, the use of idle.ignore is not
recommended, as it could cause performance issues, we should only use this if
we have a very specific use case that requires it.
4. Poll: This phase is used to check for new I/O events and process any that
have been detected.
Here is an example of how the poll phase works using a readStream:
const fs = require('fs');
console.log('Start');
console.log(chunk.toString());
});
console.log('End');
5. Check This phase processes any setImmediate() callbacks that have been
added to the message queue.
Here is an example of how the check phase works:
6. Close callbacks
setImmediate() vs setTimeout()
The order in which the timers are executed will vary depending on the context in
which they are called. If both are called from within the main module, then
timing will be bound by the performance of the process
Web Applications
1. Client
2. Server
3. Database
Client
The user interacts with the front-end part of a web application. The front-
end is usually developed using languages like HTML and CSS styles,
along with extensive usage of JavaScript-based frameworks like ReactJS
and Angular, which help with application design.
Server
The server is responsible for taking the client requests, performing the
required tasks, and sending responses back to the clients.
It acts as a middleware between the front-end and stored data to enable
operations on the data by a client.
Node.js, PHP, and Java are the most popular technologies in use to
develop and maintain a web server.
Database
The database stores the data for a web application. The data can be
created, updated, and deleted whenever the client requests.
MySQL and MongoDB are among the most popular databases used to
store data for web applications.
Requests
Node.js Server
Event Queue
Event Queue in a Node.js server stores incoming client requests and passes
those requests one-by-one into the Event Loop
Thread Pool
Thread pool consists of all the threads available for carrying out some tasks
that might be required to fulfill client requests
Event Loop
Event Loop indefinitely receives requests and processes them, and then
returns the responses to corresponding clients
External Resources
External resources are required to deal with blocking client requests. These
resources can be for computation, data storage, etc.
A web server developed using Node.js typically has a workflow that is quite
similar to the diagram illustrated below. Let’s explore this flow of operations in
detail.
Clients send requests to the webserver to interact with the web application.
Requests can be non-blocking or blocking:
-Deleting data
The requests are then passed one-by-one through the Event Loop. It checks if the
requests are simple enough to not require any external resources
A single thread from the Thread Pool is assigned to a single complex request. This
thread is responsible for completing a particular blocking request by accessing the
external resources, such as compute, database, file system, etc.
Once, the task is carried out completely, the response is sent to the Event Loop that
in turn sends that response back to the Client
Node.js Architecture comes with several advantages that give the server-side
platform a distinct upper-hand when compared to other server-side languages:
With the use of Event Queue and Thread Pool, the Node.js server enables efficient
handling of a large number of incoming requests.
Event Loop handles all requests one-by-one, so there is no need to create multiple
threads. Instead, a single thread is sufficient to handle a blocking incoming request.
Node.js server, most of the time, requires fewer resources and memory due to the way it
handles the incoming requests. Since the requests are processed one at a time, the
overall process becomes less taxing on the memory.
All of these advantages contribute to making the servers developed using Node.js
much faster and responsive when compared to those developed using other server
development technologies.
Examples of Node JS
Program – 1
output
This example is different!
The result is displayed in the Command Line Interface
Run the file on the Node.js command prompt using the command node
gk1.js i.e. node <file_name>.
Output:
Multi-
Tier (Load-Balanced) Architecture:
In a multi-tier architecture, multiple servers are used to distribute the
workload and ensure high availability.
This approach often involves load balancers that evenly distribute
incoming requests across a cluster of web servers.
Each server can serve web content independently, and if one server fails,
the load balancer redirects traffic to healthy servers, ensuring
uninterrupted service.
Working of Web Servers
There are several types of web servers, each designed for specific purposes:
a. Apache HTTP Server : Apache is one of the most popular open-source
web servers globally, known for its flexibility and robustness. It’s highly
customizable and supports a wide range of modules and extensions.
b. Nginx : Nginx is another widely used web server known for its speed and
efficiency in handling concurrent connections.
c. Microsoft Internet Information Services (IIS) : IIS is a web server
developed by Microsoft for Windows servers. It’s commonly used for hosting
websites and web applications built on Microsoft technologies like ASP.NET.
d. LiteSpeed : LiteSpeed is a commercial web server known for its high
performance and security features. It’s often used in hosting environments
where speed and security are paramount.
mkdir my-electron-app
cd my-electron-app
npm init -y
In your project directory, create two files, main.js and index.html. main.js will be the
main process, and index.html will be the renderer process.
mainWindow.on('closed', function () {
mainWindow = null;
});
}
app.whenReady().then(createWindow);
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit();
});
app.on('activate', function () {
if (mainWindow === null) createWindow();
});
Step 6: Update package.json:
Modify the scripts section in your package.json file to include a start script.
"scripts": {
"start": "electron main.js"
},
npm start
This will launch your desktop application with Electron. You can further
customize and enhance your app by exploring the Electron API and integrating
additional packages as needed.
2.3 NPM
NPM (Node Package Manager) is the default package manager for Node
and is written entirely in JavaScript.
Developed by Isaac Z. Schlueter, it was initially released in January 12,
2010.
NPM manages all the packages and modules for Node and consists of
command line client npm.
NPM gets installed into the system with installation of Node.
The required packages and modules in Node project are installed using
NPM.
A package contains all the files needed for a module and modules are
the JavaScript libraries that can be included in Node project according to
the requirement of the project.
NPM can install all the dependencies of a project through
the package.json file.
It can also update and uninstall packages.
In the package.json file, each dependency can specify a range of valid
versions using the semantic versioning scheme, allowing developers to
auto-update their packages while at the same time avoiding unwanted
breaking changes.
At the time of writing this article, NPM has 580096 registered packages.
The average rate of growth of this number is 291/day which outraces
every other package registry.
npm is open source
The top npm packages in the decreasing order are: lodash, async, react,
request, express.
Installing NPM:
To install NPM, it is required to install Node.js as NPM gets installed
with Node.js automatically.
npm –v
If the installed version is not latest, one can always update it using the
given syntax:
Node.js has a built-in module called HTTP, which allows Node.js to transfer
data over the Hyper Text Transfer Protocol (HTTP).
The HTTP module can create an HTTP server that listens to server ports and
gives a response back to the client.
Example :
Save the code above in a file called "demo_http.js", and initiate the file:
Initiate demo_http.js:
If you have followed the same steps on your computer, you will see the same
result as the example: http://localhost:8080
The first argument of the res.writeHead() method is the status code, 200
means that all is OK, the second argument is an object containing the
response headers.
Applications of Express
Express.js empowers you to construct a wide array of web applications. Here
are some captivating examples:
Express.js is known for its simplicity and flexibility which comes with
various features that helps you to build efficient and scalable web
applications.
It makes it easier to organize your application’s functionality with
middleware and routing.
It adds helpful utilities to Node.js HTTP objects and facilitates the
rendering of dynamic HTTP objects.
1. Routing
Routing is the process of handling an HTTP request that defines which
kind of response will be sent to the client on which particular request.
In Node JS, we have a module called http to create a server, where we
create a server using http.createServer and pass a callback function
to http.createServer, where we get requests and responses as s parameter
and using if else and URL, we setup routes.
Node JS:
res.end('Hello, World!');
}
Express JS:
app.get('/', (req, res) => { res.send('Hello, World!'); });
2. Middlewares
Middlewares are the middle processes that execute between processes.
In terms of web development, when we store passwords in a database
using a server, we use middleware to encrypt our passwords to make
them secure.
But Node JS does not contain any middleware by default, but we can
create our own custom middleware in it.
Instead of Node JS, Express.js contains built-in middleware
like express.static() to server static files to clients.
Syntax:
app.use(express.static('public'));
3. Error Handling
Error handling is used to ensure the smooth running of your software
or program in case of any undetected issue in your software. But in
Node JS, there is no way to handle errors automatically through any
module.
Developers can setup error handling using try catch blocks or event
emitters. But in Express JS, it is much easier to handle errors because
there are multiple ways to handle errors, like asynchronous handling,
global error handling, etc.
Syntax:
throw new Error('Error');
Request and Response means what is requested by the client side and, in
exchange for that request, what data is sent to the client side from the
server side in terms of response.
The request and response object is contained in both Node JS and
Express JS, but still, Express JS comes with multiple additional
functionalities in this object. For example, Express JS allows developers
to use parameters to access URLs, and res.send() is a much more
convenient way to send responses.
It also allows user middlewares to be used in server-side coding.
Syntax:
app.get('/', (req, res) => {
console.log(req.method);
console.log(req.url);
res.send('Hello, World!');
});
5. Body Parsing
Body parsing refers to parsing data sent from the client side to the server
side.
The client sent data in the body of the request and also sent the type of
content in headers, so converting data according to the content type is
called body parsing. In Node.js, there is no built-in method or function
to parse client-side data, but we can use modules like querystring or
buffer.
Express JS contains built-in modules to parse data without any external
modules like middleware or Express. json() Parsing.
Syntax:
app.use(express.json());
Example
Syntax:
Here, the callback function takes two arguments first is an error (if there is an
error that occurs then the renderfile returns an error), and on successful
rendering it returns a template.
Folder Structure:
Filename: app.js
Javascript
// Requiring modules
const express = require('express');
const app = express();
const ejs = require('ejs');
const fs = require('fs');
const port = 8000;
// Server setup
app.listen(port, function (error) {
if (error)
throw error;
else
console.log("Server is running");
});
Filename: index.ejs
HTML
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-
scale=1.0">
</head>
<body>
<h1>Hello World</h1>
</body>
</html>
Make sure you have installed the express and request module using the
following commands:
npm install express
npm install ejs
node app.js
Now type localhost:8000 in your browser to display the ejs page to see
the below result:
Node JS
Express JS
Mongo DB