1

I'm trying to understand what happen under the hood if I try to execute this NodeJS code :

http.createServer(function (request, response) { response.writeHead(200, {'Content-Type': 'text/plain'}); response.end('Hello World\n'); }).listen(8081);

I have 2 cases about the above code :

1 . Modify the code to do some blocking in the end line of the http.createServer callback function :

http.createServer(function (request, response) {    
    response.writeHead(200, {'Content-Type': 'text/plain'});

    response.end('Hello World\n');

    sleep(2000); //sleep 2 seconds after handling the first request 

}).listen(8081);`


//found this code on the web, to simulate php like sleep function 

function sleep(milliseconds) 
{
   var start = new Date().getTime();
   for (var i = 0; i < 1e7; i++) 
   {
      if ((new Date().getTime() - start) > milliseconds)
      {
          break;
      }
   }
}

I use this simple bash loop to do two requests to the NodeJS server

$for i in {1..2}; do curl http://localhost:1337; done

result on the client console :

Hello world #first iteration

after two second the next hello world is printed on client console

Hello world #second iteration

On the first iteration of the requests, the server can response immediately to the request. But at the second iteration of the requests, the server is blocking, and return the response to requests after two second. This is because the sleep function that blocking the request after handling the first request.

  1. Modify the code, instead of using sleep, i'm using setTimeout in the end line of the http.createServer callback function.

    http.createServer(function (request, response) {    
        response.writeHead(200, {'Content-Type': 'text/plain'});
    
        response.end('Hello World\n');
    
        setTimeout(function(){console.log("Done");}, 2000);
    
     }).listen(8081);`
    

Again i'm using this simple bash loop to do the requests

for i in {1..2}; do curl http://localhost:1337; done

The result is the response is returned to the two requests immediately. And the Hello world message is printed also immediately on the console. This because I'm using the setTimeout function which itself is an asynchronous function.

I have questions about what happen here :

1.Am I right if I say : It is the responsibility for the programmer to make asynchronous call in NodeJS code so that the NodeJS internal can continue to execute other code or request without blocking.

2.The NodeJS internal Use the Google V8 Engine to execute the javascript code and using the libuv for doing the asynchronous thing.

The Event Loop is responsible for checking is there any event associated with callback occur in the event queue and check is there any remaining code in the call stack, if the event queue is not empty and call stack is empty then callback from event queue is pushed to stack, caused the callback to be executed.

The question is :

A. When doing Async thing in NodeJS, Is that execution of callback function is separated (by using libuv thread pool) from the execution of the code in NodeJS main thread?

B. How The Event Loop handle the connections if there is multiple connection arrive at the same time to the server?

I will highly appreciated every answers and try to learn from them.

Harianja Lundu
  • 137
  • 1
  • 7

2 Answers2

1

Regarding few of your questions:

  1. It is the responsibility for the programmer to make asynchronous call in NodeJS code so that the NodeJS internal can continue to execute other code or request without blocking.

Correct! notice that it is possible (if required) to execute synchronous blocking code. As example see all the 'Sync' functions of fs module like fs.accessSync

  1. When doing Async thing in NodeJS, Is that execution of callback function is separated (by using libuv thread pool) from the execution of the code in NodeJS main thread

Node.js is single threaded, so there is no 'main thread'. When triggered, the execution of the callback function is the only code that is executed. The asynchronous design of node.js is accomplished by the 'Event Loop' as you mentioned

  1. How The Event Loop handle the connections if there is multiple connection arrive at the same time to the server?

There is no 'same time' really. one comes first, and the rest are being queued. Assuming you have no blocking code they should be handled quickly (you can and should load test your server and see how quick exactly)

Rayee Roded
  • 2,440
  • 1
  • 20
  • 21
  • 1
    I read on the web such as this http://abdelraoof.com/blog/2015/10/28/understanding-nodejs-event-loop/ , that people is talking about libuv taking care of multithreading in nodejs. whats that mean? – Harianja Lundu Dec 06 '16 at 04:18
  • @HarianjaLundu depending on the process and task, Node will delegate it to libuv, so is some cases it will be multithreaded – Mark A Dec 20 '22 at 20:40
0

First of all, I don't know what sleep does.

Basically event loop keeps a check on what resources are free and what are the needs of queued events if any. When you call setTimeout, it executes the console.log("Done") after 2 seconds. Did you program it to stop the overall execution of the function ? NO. You only asked that particular request to do something after sending down the response. You did not ask to stop the function execution or block events. You can read more about threads here. The program is asynchronous by itself.

Now if you want it to make synchronous, you need your own event loop. Can you take all of actions inside setTimeout.

setTimeout(function() {
    response.end('Hello World\n');
    response.writeHead(200, {'Content-Type': 'text/plain'});
    console.log("Done");
}, 2000);

Do you still deny other requests to stop executing? NO. If you fire 2 requests simultaneously, you will get 2 responses simultaneously after 2 seconds.

Let us go deeper and control the requests more. Let there be two global variables counter = 0 and current_counter = 0. They reside outside http.create.... Once a request comes, we assign it a counter and execute it. Then we wait for 2 seconds and and increment the counter and execute the next request.

counter = 0;
current_counter = 0;
http.createServer(function (request, response) {
    var my_count = counter; // my_count specific to each request, not common, not global
    counter += 1;

    while(current_counter <= my_count)
        if (current_counter == my_count) {
            setTimeout(function() {
                response.end('Hello World\n');
                response.writeHead(200, {'Content-Type': 'text/plain'});
                console.log("Done");
                return current_counter += 1;
            }, 2000);
        }
    }
}).listen(8081);`

Try to understand what I did. I made my own event loop in the form of while loop. It listens to the condition that current_counter equals my_count. Imagine, 3 requests come in less that 2 seconds. Remember, we increment current_counter only after 2 seconds.

Requests which came in less than 2 seconds

  1. A - current_counter = 0, my_count = 0 -> in execution, will send response after 2 seconds.
  2. B - current_counter = 0 (increments after 2 seconds only), my_count = 1 -> stuck in while loop condition. Waiting current_counter to equal 1 for execution.
  3. C - current_counter = 0, my_count = 2 -> stuck in while loop like previous request.

After 2 seconds, request A is responded by setTimeout. The variable current_count becomes 1 and request B's local variable my_count equals it and executes the setTimeout. Hence response to request B is sent and current_counter is incremented after 2 seconds which leads of execution of request C and so on.

You can queue as many requests as possible but the execution happens only after 2 seconds because of my own event loop which check for condition which in turn depends on setTimeout which executes only after 2 seconds.

Thanks !

Community
  • 1
  • 1
kawadhiya21
  • 2,458
  • 21
  • 34