Node Js (Jonas - Udemy)
Notes of Node
Last updated
Notes of Node
Last updated
Node js is a JavaScript runtime built on google's V8 engine.
Traditionally, JS was only run on the browser (Browser was the only JS runtime), but now it can also be run outside of the browser. It can now be run on another runtime environment and that env is called Node
There are now two JS runtimes - Browser and Node
3. With node, we can now use JS to access the file system, and do other things with JS which wasn't possible before. With this, we can use Node Js as a web server and use JS for server-side web development
Single-threaded, based on non-blocking i-o modal makes it efficient
Perfect for building fast and scalable data-intensive apps
There is a huge library of open-source packages for free - NPM - We call them modules or packages
An active community of developers
When building heavy server-side processing apps that require more CPU power like heavy image manipulation, video conversion, file compression, and so on (we'll see why later). We can use python, PHP, or ruby-on-rails for these kinds of apps
Why node is single threaded architecture?
Because V8 engine is single threaded, node is also single threaded. Over the time single threaded architecture of Node has provided much better performance compared to multithreaded (thread per request) architecture.
What are the different types of APIs avaialable in Node JS?
Synchronous API - Blocks the code
Asynchronous API - Dont block the code
Click on your node version on the left panel, once clicked we get all kinds of modules on the left
Run the code using the command>node index.js
and you see the output in the console.
Sync (Blocking)
Async (Non-blocking)
Each statement is processed one after another
(each line waits for the previous line to complete)
The async task happens in the background and doesn't block the normal flow of the code.
This can become a problem with slow operations (blocking)
We register a call-back function that executes once the result is available
Notice below in async code inside call-back function, the error parameter comes first and not data. Also, the encoding like utf-8
is important otherwise you will get a Buffer output like this <Buffer 72 65 61 64 2d 74 68 69 73>
There is only a single thread in the Node JS process. Meaning, for each application, there is only one thread. Thread is a set of instructions/code executed in the machine's processor. What does it mean for the node js to be single-threaded?
That means all the users who are accessing the application are all using the same thread.
This also means, when one user reads the file in a sync way, then all other users need to wait until the file read is done.
So we need to use async file read. This will make the file read in the background and doesn't block the other users' requests. PHP and other languages are multithreaded but the founder of the node found this single-threaded as an efficient way.
Callback doesn't mean asynchronous always. For some functions, it is and not for some others.
Callback functions when depends on other callbacks soon cause callback-hell and would be difficult to manage.
The Solution to CB hell would be to use ES6 Promises or ES8 async-await.
We require http
module for creating a web server so we can get the networking capabilities
We first need to create the server and need to listen to incoming requests
Let's now make use of this server created above by sending a request to this server. For this, we need to store the result of createServer inside a variable.
We can now make our server listen to the incoming requests.
Test your server
Run the command node index.js
and you see the output in the console : Server started listening on 8000 port
Meaning your server is listening now. You can now send a request to the server by typing 127.0.0.1:8000
in chrome's URL space and you see the output on your browser
When you make some changes to your server (modify your code inside const server), then ctrl+c
and then run node index.js
again in the console for the changes to take effect.
Now we are on localhost:8000. If we type localhost:8000/anything, it doesn't take us to any page but remains on the same page. Here's where routing is necessary. Routing can get complicated soon hence we use modules like Express. But for now, let's see how to implement routing in the node itself.
In line 2 we have now included the request.url
. If we type localhost:3000/test
, we get the /test and /favicon.ico in the console. Upon every request to the specific route, it also makes a request to favicon which can be ignored now.
We can use, request.url
to do a simple routing. response.writeHead()
can take response header object that can be displayed in the network tab.
Node Package Manager is a command-line app that comes included with node js used to install and manage open source packages. This comes pre-installed with node js so that we can download any package we want from npm.
In the command line, type to initialize npm
npm init
This creates the package.json file which is the file where project configuration is present.
To install any package locally,
npm install packagename
No need of --save
which was required before
To install any package globally. Once you install it globally, then it can be used in any other project folder,
npm install packagename --global
To install dev dependency, that might make the developer life easy but not actually needed for the project to work,
npm install packagename --save-dev
What is package-lock.json?
While package.json holds the dependency information of the packages/modules we installed, package-lock.json will have the information of all the dependencies used by the modules we installed. It can be therefore called dependencies of dependencies.
All the downloads will get saved in node modules
folder. You don't need to put this into git because you can download it later if required. To download all the node modules specified in package.json and package-lock.json you need the command
npm install
This downloads all the dependencies you specified as well as the dependencies used by the modules you downloaded looking at package.json and package-lock.json.
Most of the packages/modules follow this convention of numbering the version of their package. Consider this example package,
In version 1.3.4, 1 means major version, 3 means minor version, and 4 means patch version. If there are any bug fixes then the next release will be 1.3.5. If there are any features added but no breaking changes then the next version will be 1.4.0. In case of a major update where there might be breaking changes and our current code might no longer work upon update, then the next version would be 2.0.0.
To know which packages are outdated in our code, we can use
npm outdated
The ^ symbol means, we accept minor changes and bug fixes. Let's say the new release is 1.3.8 or 1.4.2 or 2.0.1 and we use the below command to update the package,
npm update
Then, since we have^
symbol that indicates we accept minor changes and bug fixes, the package gets updated to 1.4.2.
In case we use ~
symbol that indicates we accept only bug fixes then the package gets updated to 1.3.8
In case we use*
symbol that indicates we accept major changes (not recommended as it might break our current code) then the package gets updated to 2.0.1.
Node runtime has several dependencies. It depends most importantly on libraries like V8 Js Engine and Lib-UV. V8 in the node understands JS and converts it to machine code but that alone is not enough to give Node the server-side functionality. That's when Lib-UV comes into the picture. Lib-UV is an open-source library with a strong focus on Asynchronous IO. Lib-UV is what gives node the access to the computer's underlying operation system, file-system, networking, and more.
Lib-UV also implements two important features into the Node which are Event-Loop and Thread-Pool. Event-loop is for performing easy tasks such as executing call-backs whereas Thread-pool performs heavy tasks such as file-access or compression etc. V8 is written in both JS and C++ while Lib-UV is written in C++ alone.
Node not only relies on V8 and Lib-UV but also on other libraries like
http-parser - for parsing http
c-ares - for DNS requests
openSSL - for cryptography
zLib - for compression
Two fundamental parts of the Node are Event-loop and Thread-pool. Node runs on a computer/server which is a C++ program that will start the process while running.
We have a variable called process
in the node which we are going to use
In that process, the node runs on a single thread. Thread is basically a sequence of instructions of a program. Note that multi-thread means multiple sequences/parts of the same program. Since Node is single-threaded, it runs on 1 thread for 10 users or 10 million users.
When the program is initialized,
all the top-level code gets executed (code that is not inside any call-back function)
all the modules are required
all the call-backs are registered
after all this, the event-loop finally starts running. Event-loop is where most of the work is done in the app. They are the heart of the node app. But some tasks in the event-loop are too expensive to be executed in the event-loop as they may block the single thread. That's when the thread-pool comes to the rescue.
thread-pool is provided by the Lib-UV library. It gives 4 different threads that are completely separate from the main single thread. We can configure this up to 128 threads but usually, these 4 are enough. These 4 threads form the thread-pool and the event-loop automatically off-loads or delegates heavy tasks to the thread-pool. All this happens behind the scenes. The heavy tasks that might be delegated from the event-loop to the thread-pool might be File-System APIs, cryptography, and more. This way the event loop is not blocked.
Event-loop runs all the code that is inside the call-back function (not top-level code). Node is built around call-back functions which are called events that are executed at later times like timer expiring, HTTP-requests, file reading, and so on. So we call Node the Event-driven architecture. Event-loop is the one that calls all the call-backs associated with the events that are registered.
Simply put, Event-loop
receives events
calls their call-back functions
and offloads the more expensive tasks out of them to the thread pool
The order in which the events are called by event loop
There are 4 phases/ 4 callback queues of the event loop and each phase will be its own callbacks to process by the event loop
Expired timer callbacks - If there are any timer events like setTimout
whose timer gets expired, then these callbacks are first executed. If the event loop is in some other phase and the timer expires then the callback of that expired timer will be executed as soon as the event loop comes back to this phase. Callbacks are executed one by one and until all the call-backs are not completed the event loop will not go to the next phase
2.
I/O Polling and callbacks - Eventloop looks for new Input/Output events that are ready to be processed and puts them into the callback queue. I/O generally refers to tasks like networking and file access. It is in this phase where 99% of our code gets executed.
3.
Set Immediate callbacks - We can use this if we need our callbacks to be executed immediately after I/O polling callbacks.
4. Close callbacks - All close events are processed for example, shutting down a web socket or web server.
Besides these 4 callback queues there are other 2 queues
NEXTTICK() Queue
Microtask Queue
If there are any callbacks in one of these 2 queues to be processed, they will be executed right after the current phase of event loop instead of waiting for all 4 phases to be finished. In other words, after each of the 4 phases, it checks if there are any callback exists in one of these two queues and execute them if any.
Till now the 4 phases we saw was one event loop tick. Node checks whether there are any timers or I/O tasks running such as HTTP requests or file reads and so on and if there aren't any then it will exit the application. If there are then it will continue to the next tick.
How not to block the event loop since it's single-threaded?