Why is LIBUV needed in Node JS?

So, maybe this question is too noob and novice to be asked but I still have no clue why LIBUV got a place in Node JS Architecture? So here is my understanding of NodeJs architecture.

  1. Node Js is built over V8
  2. V8 is capable of running code written with EcmaScript standards.
  3. V8 is written in C++.
  4. So if you want to give any new functionality we can embed V8 in our C++ project and attach new code with new Embedded V8 in C++.

Now here is the doubt,

  1. Since V8 supports EcmaScript Javascript that means it has the capability to run callbacks written with the standards of EcmaScript.
  2. So we can add code for File System Access, HTTP server & DB access in C++ since there are libraries (header files) that gives that functionality since Java is written in C++ (correct me if I am wrong) and Java has the capability to do the same.
  3. Now if we can add this functionality in C++ where does the place for Libuv come into the picture of NodeJs architecture.

Thanks in advance and Happy Coding :)


Solution 1:

Check the docs below -

https://nodejs.org/en/docs/meta/topics/dependencies/#libuv

Another important dependency is libuv, a C library that is used to abstract non-blocking I/O operations to a consistent interface across all supported platforms. It provides mechanisms to handle file system, DNS, network, child processes, pipes, signal handling, polling and streaming. It also includes a thread pool for offloading work for some things that can't be done asynchronously at the operating system level.

So to sum it up, V8 provides the functionalities related to running JS files, but to use system resources like Network, Files, etc., libuv is used. Also it provides a threading model for accessing the resources mentioned.

Solution 2:

The libuv module has a responsibility that is relevant for some particular functions in the standard library. for SOME standard library function calls, the node C++ side and libuv decide to do expensive calculations outside of the event loop entirely.They make something called a thread pool that thread pool is a series of four threads that can be used for running computationally intensive tasks such as hashing functions.

By default libuv creates four threads in this thread pool. So that means that in addition to that thread used for the event loop there are four other threads that can be used to offload expensive calculations that need to occur inside of our application. Many of the functions include in the node standard library will automatically make use of this thread pool.

Now the presence of this thread pool is very significant. Well clearly Node.js is not truly single threaded


Libuv also gives node access to the operating system’s underlying file system such as networking. So just as the node standard library has some functions that make use of libuv thread pool it also has some functions that make use of code that is built into the underlying operating system through libuv.

Simple Http request

const https=require(“https”)
const start=Date.now()
https.request(“https://www.google.com”,res=>{
res.on(“data”,()=>{} ) 
res.on(“end”,()=>{console.log(Date.now()-start)  }) }).end()

So in this case libuv sees that we are attempting to make an HTTP request. Neither libuv nor node has any code to handle all of this low level operations that are involved with a network request. Instead libuv delegates the request making to the underlying operating system. So it's actually our operating system that does the real HTTP request Libuv is used to issue the request and then it just waits on the operating system to emit a signal that some response has come back to the request. So because Libuv is delegating the work done to the operating system the operating system itself decides whether to make a new threat or not. Or just generally how to handle the entire process of making the request.

Solution 3:

If anyone stumbles upon this and since it lacks a good answer to the OP's question, I will try to take on this.

TLDR;

  • Javascript language is not asynchronous
  • Javascript language is not multi-threaded
  • Callbacks themselves are not asynchronous, they are just mean to piggyback your code to an asynchronous operation.

Let's go over your doubts one by one.

1. Since V8 supports EcmaScript Javascript that means it has the capability to run callbacks written with the standards of EcmaScript.

Callbacks don't mean that the operation is asynchronous. A callback has got nothing to do with asynchronous execution. Callback is just a way to piggyback your function so that it executes after 'something asynchronous'.

// example of synchronous callback

function main(cb) {
  console.log('main code of the function');
  cb(); // callback invocation here
}

main(function () { 
  console.log('in callback'); 
});

Now an example of asynchronous callback

function getDataFromNetwork(url, cb) {
  ajaxCall(url).then(cb);
}

getDataFromNetwork('http://some-endpoint', function (data) {
  console.log(data);
});

This is an asynchronous call with a callback. Here getDataFromNetwork function is asynchronous not the callback. The point is that callbacks are just a mechanism of running a code after something. In an asynchronous operation, this becomes a necessity. How else we are going to do that? right?

No! Nowadays we have async-await where you can run a code after the asynchronous function completes without using callbacks.

So you get that? Callbacks are not asynchronous. And that's not the point of having libuv.

2. So we can add code for File System Access, Http server & DB access in C++ since there are libraries (header files) that gives that functionality since Java is written in C++ (correct me if I am wrong) and Java has the capability to do the same.

Yes we can add lots of code for File System Access, Http server. But Why? We do already have a lot of libraries to do that. And yes its already written in C thats how NodeJS executes them.

Java already has that? Right, but thats also a part of JVM rather than the core Java language, just like libuv is part of NodeJS runtime rather than the core Javascript language. In this regard both Java and NodeJS are similar. Its just that Java has its own C++ layer and NodeJS borrows libuv for that. BTW libuv was primarily built for NodeJS

3. Now if we can add these functionality in C++ where does the place for Libuv come in to the picture of NodeJs architecture.

I answered how these functionalities are already in C++, now lets see where libuv fits in this picture of the whole architecture.

Lets take an ajax/network call for example. Who do you think executes this?

NodeJS? No, It just gives instruction to its C++ API (Node API).

then is it Node API? No, It just gives instruction to the libuv

then is it libuv? Yes, it is

Same goes for timers, file access, child processes etc.

Also think when a lot of network calls, file access are fired within a NodeJS program, on what process it runs? who schedules them? who notify about the results and failure.

This is a lot to do. Java has its own thread pool to do that. Java has its own schedular to schedule the threads. and since Java provides threads to end user(programmers) as well. It makes sense to implement all that stuff using Java threads.

But NodeJS is single-threaded. Why it should have threads to execute I/O operations when it can borrow it from another library without making them a part of Javascript? After all, we aren't going to provide threads to the programmer so why bother?

Also Historically, Javascript was only meant to run in browsers. The only asynchronous operation browsers had access to were network requests, no file access, no DB. So we did not have a lot of bedrock already to build upon.