As they say in the website, Node.js is a JavaScript runtime built on Chrome's V8 JavaScript engine that uses an event-driven, non-blocking I/O model that makes it lightweight and efficient. But what that means and why should I start using it? Let us see.
Node.js was originally written in 2009 by Ryan Dahl after seeing a file upload progress bar on Flickr: the browser did not know how much of the file had been uploaded and had to query the Web server. Dahl criticized the limited possibilities of Apache HTTP Server (the most popular web server in 2009) to handle a lot of concurrent connections and the sequential programming way of creating code when code either blocked the entire process or implied multiple execution stacks in the case of simultaneous connections.
Dahl demonstrated the project at the inaugural European JSConf on November 8, 2009 and the project received a standing ovation. Its development and maintenance was led by Dahl and later sponsored by Joyent. In January 2010, npm was introduced. This package manager makes it easier for programmers to publish and share source code of libraries and is designed to simplify installation, updating and uninstallation of libraries.
In December 2014, Fedor Indutny started io.js, a fork of Node.js, that was created as an open governance alternative with a separate technical committee. Later in February 2015, the intent to form a neutral Node.js Foundation was announced and the Node.js and io.js communities voted to work together under the Node.js Foundation on June 2015 and they were merged back together into Node v4.0 in September 2015.
Now, you know that Node.js is a server. Well, let me show you how can I start using it:
var http = require('http');
var server = http.createServer(function(request, response) {
// Your own JavaScript code
});
Easy, right? The next JavaScript code shows a complete example that deals with the most common features of a HTTP request in a Node.js server that listens in the port 8080.
var http = require('http');
http.createServer(function(request, response) {
var headers = request.headers;
var method = request.method;
var url = request.url;
var body = [];
request.on('error', function(err) {
console.error(err);
}).on('data', function(chunk) {
body.push(chunk);
}).on('end', function() {
body = Buffer.concat(body).toString();
response.on('error', function(err) {
console.error(err);
});
response.writeHead(200, {
'Content-Type': 'application/json'
})
var responseBody = {
headers,
method,
url,
body
};
response.end(JSON.stringify(responseBody))
});
}).listen(8080);
A bit more complex:
var http = require('http');
http.createServer(function(request, response) {
request.on('error', function(err) {
console.error(err);
response.statusCode = 400;
response.end();
});
response.on('error', function(err) {
console.error(err);
});
if (request.method === 'GET' && request.url === '/echo') {
request.pipe(response);
} else {
response.statusCode = 404;
response.end();
}
}).listen(8080);
In the code above I have configured a server that listens in the port 8080 and only allows requests from /echo using the GET method. As you can see, it handles errors at the beginning and later, responses to the request in case it is well formed. It is an echo endpoint.
Blocking is when the execution of additional JavaScript in the Node.js process must wait until a non-JavaScript operation completes. This happens because the event loop is unable to continue running JavaScript while a blocking operation is occurring.
All of the I/O methods in the Node.js standard library provide asynchronous versions, which are non-blocking, and accept callback functions. Some methods also have blocking counterparts, which have names that end with Sync.
Take a look at the next synchronous code:
const fs = require('fs');
const data = fs.readFileSync('file.md');
console.log(data);
console.log('Process ends')
and this is the equivalent asynchronous code:
const fs = require('fs');
fs.readFile('file.md', (err, data) => {
if (err) throw err;
console.log(data);
});
console.log('Process ends')
In the first example, the text Process ends will be printed when the file is completely read, but the second example will print the text Process ends before the file is completely read. It is a powerful feature that allows to allow multiple connections without blocking processes.
Well, I told you that Node.js is really powerful and easy to use. The current API is really big and allows you to do it a lof of things. Take a look on https://nodejs.org/api/ taking special attention in Debugger, File System, Process and Stream.