You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
a very common use case for Nodejs is to build Servers
in Nodejs, server and the application are the same
consthttp=require('http');consthostname='127.0.0.1';constport=3000;constserver=http.createServer((req,res)=>{res.statusCode=200;res.setHeader('Content-Type','text/plain');res.end('Hello World');});server.listen(port,hostname,()=>{console.log(`Server running at http://${hostname}:${port}/`);});
Difference between Blocking and Non-Blocking Calls in Nodejs
Blobking methods execute synchronously and non-blocking methods execute asynhcronously
execution of additional JS in Nodejs process must wait until the execution of non-JS operation completes (blocking operation)
this happens because event loop is unable to run JS code until blocking operation completes
Most commonly used synchronous methods are from Nodejs standard library
All I/O methods in Nodejs standard library have asynchronous versions which are non-blocking and and accept callback functions
Example of Synchronous file read:
constfs=require('fs');constdata=fs.readFileSync('/file.md');// blocks here until file is readconsole.log(data);// moreWork(); will run after console.log
Example of Asynchronous file read:
constfs=require('fs');fs.readFile('/file.md',(err,data)=>{if(err)throwerr;console.log(data);});// moreWork(); will run before console.log
Concurrency
JavaScript execution in Node.js is single threaded, so concurrency refers to the event loop's capacity to execute JavaScript callback functions after completing other work. Any code that is expected to run in a concurrent manner must allow the event loop to continue running as non-JavaScript operations, like I/O, are occurring.
Event-driven programming is a programming paradigm in which the flow of the program is determined by events such as user actions (mouse clicks, key presses), sensor outputs, or messages from other programs/threads.
In practice, it means that applications act on events.
Nodejs Thread Model
Nodejs is single threaded
Event Loop provides Nodejs the event driven Programming
Event Loop schedule tasks(/events)
Each time an event occurs, it is placed in Node's event queue
On each iteration of event loop, a single event is dequeued and processed
If during the process, the event creates any additional events, they are simply added to the end of the queue along with a callback
NodeJS uses callbacks to avoid waiting for blocking I/O.
When the event is executed, control is returned to the event loop and another event is processed.
When all events on NodeJS event queue are executed, NodeJS terminates the application.
Nodejs System
Building blocks of NodeJS:
Reactor Pattern
libuv
Set of Bindings
V8
Core JS Library
I/O is Slow
I/O is the fundamental operation of a computer
it is slow
Accessing the RAM is matter of nanoseconds
While accessing the data on disk or network is a matter starts in milliseconds
Blocking I/O
Traditionally, a system calls an I/O request that comes to a webserver and is assigned to an available thread
for each concurrent connection there is a thread
The request is handled continuously on that thread until the request is complete and response is sent.
while handling the data between Functions such as GetFile(file) & Open(File) there will be some amount of idle time
thread consumes memory, so long running thread for each connection & not using it is not efficient.
Traditional Non-Blocking I/O
system call is returned immediately without waiting for the data to be read or written (aka operation to complete)
If no results are available at the moment of the call, the function will simply return a predefined constant, indicating that there is no data available to return at that moment.
A loop iterate over the resource and when resource is found (operation is completed) it is returned.
This loop consumes CPU for iterating over the resource that are unavailable most of the time.
This is called busy-waiting. Traditional Non-Blocking I/O.
Event Demultiplexing
modern way of Non-Blocking I/O
for efficient Non-Blocking I/O there is synchronous event-demultiplexer (aka:event notification interface)
It collects and queues I/O events that come from requests and block(sits idly ) until new events are available to process.
Each event is associated with a specific operation
Event notifier is set on the group of resources to be watched
This call is synchronous and blocks(idle time) until any of the watched resources is ready for a read
Event Demultiplexer returns from watched resources when they are being processed and a new set of events are available to be processed.
Each event returned by the event demultiplexer is processed.
When all the events are processed, the flow will block again(there will be idle time in between) on the event demultiplexer until new events are again available to be processed. This is called the event loop.
This way several I/O operations can be handled in a single thread.
Advantages:
minimalize idle time
having a single thread handle multiple requests
Reactor Pattern
have a handler(in case of Nodejs, have a callback function) associated with each I/O operation
this handler/callback function is invoked when event is produced & processed by Event Loop.
What happens in an Application using the Reactor Pattern?
application generates I/O request by submitting request to Event Demultiplexer
The application also specifies handler/callback function which will be invoked when operation completes
Submitting a new request to the Event Demultiplexer is a non-blocking call and it immediately returns the control back to the application.
When I/O operation completes, the Event Demultiplexer pushes the new events into the Event Queue.
At this point, the Event Loop iterates over the items of the Event Queue.
For each event, the associated callback function is invoked.
callback function will give control to the event loop when its execution completes.
New asynchronous operations might be requested during the execution of the callback function, causing new operations to be inserted in the Event Demultiplexer
When all items in Event Queue are processed, and there no pending operations in Event Demultiplexer, Node.js application will exit automatically.
libuv - Non-Blocking I/O Engine
pronounced as "lib u v"
Each operating system has its own interface for the Event Demultiplexer
eg: epoll on Linux, kqueue on Mac OS X & IOCP on Windows
each I/O operation can behave quite differently depending on the type of the request, even within the same OS.
this creates inconsistency
to overcome this inconsistency, Nodejs Core team built libuv
libuv is a C library, created to make Node.js compatible with every OS & normalize the non-blocking behavior of the different OS types.
libuv is a low-level I/O Engine
it implements Reactor Pattern, providing an API for creating even loop, managing event queue, running asynchronous I/O operation.
Set of Bindings
responsible for wrapping and exposing libuv and other low-level functionality to JavaScript.
V8
JavaScript runtime engine
compiles and executes JS
developed by Google for Chrome browser
reason why Nodejs is fast
V8 is acclaimed for its revolutionary design, its speed, and for its efficient memory management.
Core JS library
A core JavaScript library (called node-core) that implements the high-level Node.js API.
referred as Continous Passing Style (CPS) programming
async functions take an extra argument
a function that is called after the async code has finished executing
this extra argument is referred as continuation or callback function
Important Convention: if a function takes a callback function as an argument, it should be the final argument. Also, if the same function takes an error as an argument, that should be the first argument
Callback?
function that is executed asynchronously (or at a later time in the event loop)
asynchronous programs execute different functions at different time based function's speed and order. (Eg: a file read from system will take more time)
An Example of Blocking I/O, Non-Blocking I/O & Callback
Consider that you are visiting a fast food joint where you order a burger at cash counter. The cash counter will take your order and will make you wait for your order to complete. In the mean time, the cash counter can take other orders and start cooking them for other people too.
If you are made to wait at the cash counter for your order, blocking all other customers in line from ordering while the fast food joint completes your order. That's BLOCKING I/O since completing orders happen one at a time. There will be some amount of idle time while the food is being cooked.
Nodejs in NON-BLOCKING, meaning it can take as many orders and complete them based on the time taken to cook a particular order.
Now, imagine that the fast food joint has given you number on your table while you wait for your meal. That's a callback (the number).
Callback Hell
occurrs when callbacks are nested within callbacks
In Node.js, files and modules are in one-to-one correspondence (each file is treated as a separate module)
require()
to import modules into nodejs programs (importing aka module loading)
accepts single argument as string:
path to the module
if path exists, returns an object to interact with module
require is one of the few synchronous I/O operations available in Node. Because modules are used often and are typically included at the top of a file, having require be synchronous helps keep code clean, ordered, and readable.
Core Modules
modules compiled in Node binary
highest precedence given by require()
meaning if there are two modules of the same name and one of them is core module, require will load core module
File Modules
non core modules
loaded from the file system
module path begins with (.) or (..) as relative paths
If the module path does not correspond to core module or filesystem module, Node begins searching for the module in node_modules directory (such as in case of third party modules)
Module Caching
Modules are cached after the first time they are loaded
meaning every call to require('foo') will return the same object
multiple calls to require('foo') may not cause the module to execute mutliple times
module Object
module represents the current module
module.exports defines what a module exposes that is available through require
exports is a property of module Object, act as a reference to module.exports
Exporting Node Modules
allows developer to select what functions from the included files are exposed to the main application:
use module.exports = function functionName(){} if module is returning a single function
use exports.functionName = function(){} when module is returning more than one function
if you create a module that populates both exports and module.exports, module.exports will be returned and exports will be ignored.
Everything is local in Nodejs Module
By default, JS puts everything into global scope. Node.js is designed to behave differently, with being local by default
Top-level scope in Node.js is not global scope. var a inside a Node.js module is local to that module