Let’s discuss Node.js. Why we use node.js for single-page application?
We know JS language is used to create applications more interactive. Now, it is used with desktop, mobile, and web applications and servers.
Web applications which we request from the client are stored in a web server and we termed this as client-server communication. Now, we just look at some kind of requests that we normally know.
If a client requests some kind of calculations to the server then it takes x milliseconds and returns the result as the response. This is called CPU intensive.
If a client requests any data from the server and that may be fetched from other resources like database, file system, another server. This is called I/O intensive. This work may take x seconds.
Consider a scenario. We have only one client at this moment and the request sent to the server is an I/O intensive. It took 5 seconds(let’s say) to respond. Now, think if we have multiple clients then it took the request of the next client after 5 seconds only.
To avoid this, we use threads. Let consider the Tomcat server which contains 200 threads by default. Based on the parameter we set in the config.xml file, the number of threads in the pool will be assigned. So, if we send a request to the server that will be assigned to a threat (T1) and then the second request will be assigned to a thread(T2)….(T200). By doing this, we can respond to the requests parallel (i.e.) every request takes 5 seconds(let’s say).
Then think what if there are 202 clients? Because we know by default it has 200 threads. So, 200 client requests will be assigned to 200 threads, and the remaining 2 clients will wait for the thread.
Node.js as a web server
We know the node.js web server has only one thread and that accepts the request from the client.
Now, a client requests an I/O intensive request then that one thread will accept and requests the data to be fetched from the database or other resources. At this moment, another client is requesting data. We know, client2 has to wait until client1 request is fulfilled. Just think, If we have multiple clients and they have to wait for x seconds for accepting their requests. Clients won’t tolerate this.
It has only one thread for accepting the request since it’s JS based and this part works fine but feels exhausted when we request I/O intensive and wait for the response. Now we handle this by giving that accepted request’s work to worker threads. Now we got a point right.
A client requests data to be fetched from the database. So, this request is accepted by the single thread and asks its worker thread to fetch the data. Now, the worker thread only fetches the data from the database at this moment that single thread is accessible and free to accept the other client’s request. After fetching the data, the worker thread handed over the data to a single thread and it will send the response to the requested client. There is no kind of communication between client and worker thread. A single thread in node.js only communicates with its worker thread. This is called Non-blocking I/O.
A single thread needs to know which response is given to which client. We know the requested client will wait for its response but the single thread will accept the request alone and the worker thread will fetch data from resources and be given to a single thread. This scenario happens asynchronously.
Every request is given by a single thread to a worker thread executed asynchronously. Worker thread executes callback function which fetches data and returns the data to the single thread which identifies the details about the client from the callback function.
CPU intensive has more complex calculations and this won’t be used in node.js. Because long-running CPU tasks will block the whole server. To more specific, CPU-intensive tasks runs on a single thread and in an event-loop then think when this thread is blocked, all other tasks would have to wait.
Option: To have the CPU work, it would be written as a separate process and make node.js interact with those instead of doing themselves.
So, node.js isn’t executing parallel only I/O runs parallel and executes asynchronously.
Is node.js partially supports multiple threads? Probably, Not. Then how that single thread supports worker threads?
We know node.js is a set of libraries that runs on top of the JS engine. It has some dependencies.
- libuv -used to abstract non-blocking I/O operations.
- V8 -maintained by Google and used for chrome.
- lhttp — for handling HTTP parsing.
- c-ares -for some asynchronous DNS requests.
- OpenSSL -for implementing cryptographic functions.
- zlib -to create sync, async and streaming compression, decompression interfaces.
Now, we consider V8 and libuv.
V8 is 70% c++ and 30% JS.
Libuv is 100% C.
Libuv is a library that provides a set of threads to node.js just to execute tasks. By default, 4 threads to each node process are provided. It is built in C language and uses a system kernel that has multiple threads. This acts as a worker thread.
So, node.js isn’t using multiple threads but the worker thread is implementing multiple threads using kernel.
Worker thread has one process, multiple threads, one event loop per thread, one JS engine instance per thread, one node JS instance per thread.
Single page application
Simply, web applications that run inside the browser or loading the requested application without refreshing the pages. For making this, we use many concepts and node.js is the major and one of the concepts for SPA. Node.js allows server-side rendering.
So, Node.js is a runtime environment that helps to interpret the JS-based coding by browser’s engine. For routing, it needs HTTP modules and that may be implemented using its framework like Express.js.
While developing an application by full-stack you can understand how it works as a server-side rendering. Since it is considered as a back-end and dependencies, framework and libraries are to be included.
Let’s consider YouTube. Streaming a video that doesn’t make you download the audio and video all at once. Instead, our browser receives the video as a continuous flow of chunks, allowing the client to watch.
So, Streams are one of the fundamental concepts that power Node.js applications. They are data-handling method and are used to read or write input into output sequentially.