Experimenting with NodeJS

Published:

Add / read comments

Well, over last two years, my attention to Node.js was growing. So I finally decided to examine what is really going on :-) Node.js is an open source (which is great), cross-platform runtime environment for server-side and networking applications.

Node.js provides an event-driven architecture and a non-blocking Input/Output API that optimizes an application's throughput and scalability. Asynchronous technologies are commonly used for real-time applications. Node.js applications are written in JavaScript, and can be run within the Node.js runtime on Microsoft Windows, Linux, OS X with no changes.

Node.js internally uses the Google V8 JavaScript engine to execute code, and a large percentage of the basic modules are written in JavaScript. Node.js contains a built-in asynchronous I/O library for file, socket, and HTTP communication, which allows applications to act as a Web server without software such as Apache HTTP Server or IIS.

First important thing is to get Node.js runtime environment working on your own machine. I found some useful videos on the internet, so it is not problem to make Node.js environment running. All the information and download file can be found on official Node.js website.

So once Node.js is running on our machine, let's write first program. Open your IDE or favorite editor and write following:

// Load the http module to create an http server.
var http = require('http');
var url = require("url");
var count = 0;
 
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(
 
  function (request, response) {
 
    // parse requested URL path
    var pathname = url.parse(request.url).pathname;
 
    // message into terminal
    console.log("Request for " + pathname + " received.");
 
    response.writeHead(200, {"Content-Type": "text/html"});
 
    count++;
 
    response.write("<br />Number of requests: "+count+"");
    response.end("<br />End of response!");
  }  
 
);
 
// Listen on port 3000, IP defaults to 127.0.0.1
server.listen(3000);
 
// Put a friendly message on the terminal
console.log("Server has started at http://127.0.0.1:3000/");

Name your file (for example: basic.js), save it and then run in the terminal following command:

node path/to/your/file/basic.js 

Now, if you open the web browser and type http://127.0.0.1:3000/ you should see something like this:

Number of requests: 1
End of response!

But if you look into the terminal, you will see log messages:

Server has started at http://127.0.0.1:3000/
Request for / received.

And everytime browser is refreshed (F5), the will be new message in the terminal.

Well, lets try to measure time of program execution. How fast is Node.js. So try the following example:

// Load the http module to create an http server.
var http = require('http');
var url = require("url");
var count = 1;
 
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(
 
  function (request, response) {
 
    // parse requested URL path
    var pathname = url.parse(request.url).pathname;
 
    response.writeHead(200, {"Content-Type": "text/html"});
 
    var Start = new Date();
    var i = 0;
 
    // do long term while cycle 4e9 is 4 000 000 000 which is 4 bilions	
    while ( i < 4e9){
  	i++;
    }
 
    var End = new Date();
 
    // display time execution	
    response.write('Function started at: ' + Start.toString() + ' and finished at:' + End.toString() + ' and took: ' + (End.getTime() - Start.getTime()) + 'msec');            
 
    response.write("<br />Number of requests: "+count+"");
    response.end("<br />End of response!");
 
    count++;
  }  
 
);
 
// Listen on port 3000, IP defaults to 127.0.0.1
server.listen(3000);
 
// Put a friendly message on the terminal
console.log("Server has started at http://127.0.0.1:3000/");

Now, if you open the web browser and type http://127.0.0.1:3000/ you should see something like this:

Function started at: Sun Oct 12 2014 18:46:06 GMT+0200 (Central Europe Daylight Time) and finished at:Sun Oct 12 2014 18:46:12 GMT+0200 (Central Europe Daylight Time) and took: 6199msec
Number of requests: 1
End of response!

But what about that non-blocking code?

As you noticed, you had to wait aproximatelly 6 seconds for server response (depends on your computer). It's because function was long. That's all right. But what if we refresh browser multiple times? Then we have to wait until first request is executed and then others are going to be executed. I refreshed three times and had to wait almost 18 seconds for browser response. It means that previous request was blocking next one.

Now, let's take a look onto non-blocking rogram. For this purpose, Node.js has process.nextTick(). Function nextTick is more efficient alias to setTimeout(fn, 0) By using nextTick function, we ensure that if any other HTTP requests are queued in the event loop, they will be processed before the next time nextTick function gets invoked. If we had not used process.nextTick() and had simply called long term function, the program would not have been able to process any incoming HTTP requests. The program would be blocking.

// Load the http module to create an http server.
var host = '127.0.0.1';
var port = 3000;
 
var http = require('http');
var url = require("url");
var count = 1;
 
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(
 
  function (request, response) {
 
    // parse requested URL path
    var pathname = url.parse(request.url).pathname;
    // message into terminal
    console.log("Request for " + pathname + " received.");
 
    response.writeHead(200, {"Content-Type": "text/html"});
 
    var i = 0;
 
    process.nextTick( function() {
 
        var Start = new Date();          
        console.log( 'Loop started at: ' + Start.toString() );
 
        // do long term while cycle 2e9 is 2 000 000 000 which is 2 bilions	
        while ( i < 2e9){
            i++;
  	}
 
        var End = new Date();              
        console.log( 'Loop ended at: ' + End.toString() );
 
        // display time execution in terminal	
	console.log('Loop execution time took: ' + (End.getTime() - Start.getTime()) + 'msec');            
 
    }, 1000 );    	  
 
    response.write("<br />Number of requests: "+count+"");
    response.end("<br />End of response!");
 
    count++;
  }  
 
);
 
// Listen on port 3000, IP defaults to 127.0.0.1
server.listen(port, host, function(){
 
    // Put a friendly message on the terminal
    console.log("Server has started at http://127.0.0.1:3000/");
 
});

Now, if you open the web browser and type http://127.0.0.1:3000/, after very short time (22msec in my case) you should see something like this:

Number of requests: 1
End of response!

And in the terminal will appear step by step after few second:

Request for / received.
Loop started at: Mon Oct 13 2014 19:55:23 GMT+0200 (Central Europe Daylight Time)
Loop ended at: Mon Oct 13 2014 19:55:29 GMT+0200 (Central Europe Daylight Time)
Loop execution time took: 5917msec

But if we refresh web browser multiple times (3 times in my case). We will have to wait for response much longer (11,32s in my case). So the response is long, but server was working parallely on requests and total time was much shorter, because otherwise would take approximately 18 seconds. In the terminal was mesage:

Request for /a received.
Loop started at: Mon Oct 13 2014 19:55:35 GMT+0200 (Central Europe Daylight Time)
Loop ended at: Mon Oct 13 2014 19:55:41 GMT+0200 (Central Europe Daylight Time)
Loop execution time took: 6003msec

Request for /a received.
Loop started at: Mon Oct 13 2014 19:55:41 GMT+0200 (Central Europe Daylight Time)
Loop ended at: Mon Oct 13 2014 19:55:47 GMT+0200 (Central Europe Daylight Time)
Loop execution time took: 6021msec

Request for /a received.
Loop started at: Mon Oct 13 2014 19:55:47 GMT+0200 (Central Europe Daylight Time)
Loop ended at: Mon Oct 13 2014 19:55:53 GMT+0200 (Central Europe Daylight Time)
Loop execution time took: 5904msec

Another way to run more I/O operations is module async.parallel So try the following example:

// Load the http module to create an http server.
var host = '127.0.0.1';
var port = 3000;
 
var http = require('http');
var url = require('url');
var async = require('async');
var count = 1;
 
function runComputing ( callback ) 
{
    setTimeout ( function( ) 
    {  
        var i = 0;
 
        var Start = new Date();          
        console.log( 'Function loop started at: ' + Start.toString() );
 
        // do long term while cycle 2e9 is 2 000 000 000 which is 2 bilions	
        while ( i < 2e9){
  	    i++;
        }
 
        var End = new Date();              
        console.log( 'Function loop ended at: ' + End.toString() );
 
        // display time execution in terminal	
        console.log('Function loop execution time took: ' + (End.getTime() - Start.getTime()) + 'msec');  
 
        callback(null, ["computed value: " + i]);          
 
    }, 1000 );    	  
}
 
// Configure our HTTP server to respond with Hello World to all requests.
var server = http.createServer(
 
  function (request, response) 
  {  
    // parse requested URL path
    var pathname = url.parse(request.url).pathname;
    // message into terminal
	  console.log("Request for " + pathname + " received.");
 
    async.parallel({
        computingResult: runComputing,
    }, 
    function (err, data) {
 
      console.log("Computing done: ", data);
 
    });
 
    response.writeHead(200, {"Content-Type": "text/html"});
    response.write("<br />Number of requests: "+count+"");
    response.end("<br />End of response!");
 
    count++;
  }    
);
 
// Listen on port 3000, IP defaults to 127.0.0.1
server.listen(port, host, function(){
    // Put a friendly message on the terminal
    console.log("Server has started at http://127.0.0.1:3000/");    
});

Now, if you open the web browser and type http://127.0.0.1:3000/, after very short time (21msec in my case) you should see something like this:

Number of requests: 1
End of response!

And in the terminal will appear messages:

Server has started at http://127.0.0.1:3000/
Request for /a received.
Function loop started at: Tue Oct 14 2014 21:03:03 GMT+0200 (Central Europe Daylight Time)
Function loop ended at: Tue Oct 14 2014 21:03:05 GMT+0200 (Central Europe Daylight Time)
Function loop execution time took: 2218msec
Computing done:  { computingResult: [ 'computed value: 2000000000' ] }

But if we refresh web browser multiple times (3 times in my case). We will have to wait only very short time (7ms in my case). So the response is much shorter than in previous examples. So by using async.parallel module, we can shorten time of response significantly. Long term computing is processing and when it's done, will send message into terminal:

Request for /path received.
Request for /path received.
Request for /path received.

Function loop started at: Tue Oct 14 2014 21:06:12 GMT+0200 (Central Europe Daylight Time)
Function loop ended at: Tue Oct 14 2014 21:06:14 GMT+0200 (Central Europe Daylight Time)
Function loop execution time took: 2238msec
Computing done:  { computingResult: [ 'computed value: 2000000000' ] }

Function loop started at: Tue Oct 14 2014 21:06:14 GMT+0200 (Central Europe Daylight Time)
Function loop ended at: Tue Oct 14 2014 21:06:16 GMT+0200 (Central Europe Daylight Time)
Function loop execution time took: 2194msec
Computing done:  { computingResult: [ 'computed value: 2000000000' ] }

Function loop started at: Tue Oct 14 2014 21:06:16 GMT+0200 (Central Europe Daylight Time)
Function loop ended at: Tue Oct 14 2014 21:06:18 GMT+0200 (Central Europe Daylight Time)
Function loop execution time took: 2228msec
Computing done:  { computingResult: [ 'computed value: 2000000000' ] }

So based on my little experiments, the best way to not block web page response and handle some function requiring long "heavy" computing is to use async module and parallel style.

Published:

Add / read comments

FIND ME

Share, follow or connect with me.