Node.js


Node is an open source runtime environment for server-side applications. It allows you to run JavaScript on the server in addition to the browser. Almost all of the new and most widely used JavaScript solutions use Node in one form or another.

Installing Node.js

Download from https://nodejs.org. Install with default options. To check, type the following on the terminal

$ which node

If you see a path like the following, nodejs is installed and you can start coding:

/usr/local/bin/node

First Program

Type the following command in your non-formatting editor of choice such as sublimetext or nodepad++.

console.log(“Hello World”);

Save this file as hello.js. Type the following command to run the code:

$ node hello.js

Process Object

The process object is available globally meaning that it can be accessed from anywhere in the code. It allows us to fetch information regarding the current process instance; information such as environmental variables, path, stdin, and stdout.

console.log(process.argv);

Save this code as processdemo.js. To run:

$ node processdemo.js

This code outputs the parameters used when the process starts. It’s output is as follows:

[ '/usr/bin/node', '/Users/testing/exercises/processdemo.js' ]

If I run the command with parameters:

$ node processdemo.js id name

The output will be:

[ '/usr/bin/node', '/Users/testing/exercises/processdemo.js' ,'id','name']

To get an individual parameter, simply print the specific element in the process.argv array by it’s index

console.log(process.argv[3]);

will output:

name

process.stdout.write prints to the terminal. process.stdin.on adds a listener event. See the example below.

var question = "Say something?";
var answer = "";

function prompt() {
  process.stdout.write(`\n ${question}: `);
}

process.stdin.on('data', function(data) {
  answer = data.toString().trim();
  process.exit();
});

process.on('exit', function() {
  process.stdout.write(`\nYou said ${answer}\n`);
});

prompt();

In this program, we begin from the call to prompt() function at the bottom. prompt() function prints the question to the terminal using stdout.write function(). process.stdin.on(‘data’…) is an event listener that listens for data. Once you type something and hit return, process.on(‘exit’..) function is called. It prints your response to the question.

Synchronous and Asynchronous Communication

Node support both synchronous and asynchronous communication. What is the difference? Synchronous communication is sequential communication. You can only run one job at a time and all jobs need to wait for their turn to run. In asynchronous communication, the jobs can run in parallel depending on available resources. Following is a simplified example.

Suppose you call your Internet service provider and need to speak to a representative. You will be placed on hold until someone becomes available. This is synchronous communication. You are put on hold and you cannot do anything else. Some companies give you the option of a callback. You call in and leave a callback number. When a representative is free, he or she will call you back. You are free to do other things until you turn comes up. You are not on hold. This is asynchronous communication.

In asynchronous programming, a callback is equivalent of function. It is called after a task is completed.

Following code will synchronously list contents of a directory:

fh = require(‘fs’);
content = fh.readdirSync(‘mydirectory’);
console.log(content);

Following code will asynchronously list contents of a directory

fh = require(‘fs’);
content = fh.readdir(‘mydirectory’);
console.log(content);

Except for the function name, the rest is the same.

Built-in Modules

A module encapsulates relate code, such as code for handling files, into a single unit of code. Node ships with many useful modules. These are called built-in modules. Programmers can create new modules. These are called custom modules.

Following is a list of some built-in modules:

ModuleDescription
assertused for unit testing
bufferfor handling binary data
cryptofor openssl
eventsfor event handling
fsfile handling
httpmake Node.js act as an HTTP server
httpsmake Node.js act as an HTTPS server
netcreate clients and servers
osgives info about the os
pathhandling file paths
querystringhandle url querystring
readlinehandle readable streams
streamhandle streaming data
timerstiming functions like counting milliseconds
tlsfor implementing TLS and SSL protocols
urlparsing URL strings
utilutility functions
zlibTo compress or decompress files

Assert

Following is a simple example of testing an expression:

var assert = require('assert');
assert(1 > 10);

Since 1 not greater than 10, the assertion fails with the following error:

assert.js:81
  throw new assert.AssertionError({
  ^
AssertionError: false == true
    at Object.<anonymous> (nodejs-ex/assert.js:3:1)
    at Module._compile (module.js:570:32)
    at Object.Module._extensions..js (module.js:579:10)
    at Module.load (module.js:487:32)
    at tryModuleLoad (module.js:446:12)
    at Function.Module._load (module.js:438:3)
    at Module.runMain (module.js:604:10)
    at run (bootstrap_node.js:389:7)
    at startup (bootstrap_node.js:149:9)
    at bootstrap_node.js:502:3

Crypto

The crypto module offers many functions for encrypting and decrypting strings, streams, and buffers. Following example encrypts and decrypts a string:

var cry = require('crypto'), algo = 'aes128', pass = 'UY675ygyf$$';

function encrypt(txt){
  var cipher = cry.createCipher(algo,pass)
  var enc = cipher.update(txt,'utf8','hex')
  enc += cipher.final('hex');
  return enc;
}

function decrypt(txt){
  var decipher = cry.createDecipher(algo,pass)
  var dec = decipher.update(txt,'hex','utf8')
  dec += decipher.final('utf8');
  return dec;
}

var mystring = encrypt("Encrypt me")
console.log(mystring);
console.log(decrypt(mystring));

Output:

e25c9392c7702ed52aef43ae0a48a78a
Encrypt me

Streams

We have already seen how to read stdin (input from the terminal) as follows:

console.log(process.stdin);

A program can take input from many different sources of streaming data. Readline module provides an interface to read data from any Readable stream including process.stdin. See https://nodejs.org/api/readline.html. Following is a simple example, I picked up from Readline documentation.

const readline = require('readline');

const rl = readline.createInterface({
  input: process.stdin,
  output: process.stdout
});

rl.question('What do you think of Node.js? ', (answer) => {
  console.log(`Thank you for your valuable feedback: ${answer}`);
  rl.close();
});

The first line requires the module. It is a core module so you don’t need to install anything using npm. The next block defines the input and output source for the interface. We specified stdin as data source and will output to stdout. The last block prompts a question and then prints the response in the console.

Data can come from or go to many different sources such as text files, JSON, and XML. Streams are objects that allow you to read from or write to a data source.

EventEmitters for streams are:

  • Data: when data is available for reading
  • End : when there is no more data to read
  • Error: where there is an error read from or writing to a stream
  • Finish: when you are done using the stream

The following code show how to read from a file using these EventEmitters:

var fs = require("fs");
var content = '';

// open file and create stream for reading
var rs = fs.createReadStream('in.txt');

// read from the file
rs.on('data', function(txt) {
  console.log(txt);    
  content += txt;
  console.log(content);
});

// done reading
rs.on('end', function(){
  console.log('done reading');
})

// print any errors          
rs.on('error', function(err){
  console.log(err.stack);
})   

Save this file as readfromfile.js. Create a text file, in.txt with the following contents and save in the same directory as readfromfile.js.

one
two
three

The output:

<Buffer 6f 6e 65 0a 74 77 6f 0a 74 68 72 65 65>
one
two
three
done reading

Note that the first line output is the print out of the stream, so it is a buffer. When we assign the buffer to a text variable, it is converted to string data.

Code to append to a file, simply use the following code

var fs = require("fs");
var as = fs.appendFile('in.txt','four');

It appends the word four to the file. To write to a new file,

var fs = require("fs");
var content = 'Four';

// write stream to file
var ws = fs.createWriteStream('out.txt');
ws.write(content);
ws.end();

ws.on('error', function(err){
  console.log(err.stack);
});

This code writes the word Four in out.txt file. If the file does not exist, it will create it. If it exists, it will be overwritten. The following code pipes contents of an input file into an output file.

var fs = require("fs");

// create read and write streams and pipe them
var rs = fs.createReadStream('in.txt');
var ws = fs.createWriteStream('out.txt');
rs.pipe(ws);

Events

Node.js is an event-driven system. When you are performing different tasks, different events are emitted. You need to understand those events and how to use them. Events are defined by different modules. For example process.on() is an event. You can also create and use your own events. See example:

var events = require('events');
var eventEmitter = new events.EventEmitter();

eventEmitter.on('bankrupt', function() {
    console.log('You are bankrupt');
});

var networth = -20000;
if (networth < 0) {
    eventEmitter.emit('bankrupt');
}

output:

You are bankrupt

If the networth is less than 0, this event emitter prints a message to the console.

File Management

Node uses the fs library to provide rich and powerful file management functionality. First let’s a directory and some files:

$ mkdir data; cd data
$ touch provinces.txt capitals.txt

Add the following text to provinces.txt

Alberta
British Columbia
Manitoba
New Brunswick
Newfoundland and Labrador
Nova Scotia
Ontario
Prince Edward Island
Quebec
Saskatchewan

Add the following to capitals.txt

Charlottetown
Edmonton
Fredericton
Halifax
Ottawa
Quebec
Regina
St. John's
Toronto
Victoria 
Winnipeg

Following code lists the files in a directory. It runs synchronously so not recommended for big files:

var fs = require("fs");
var files = fs.readdirSync("./data");
console.log(files);

Output:

[ 'capitals.txt', 'provinces.txt' ]

The following code lists files in a directory asynchronously:

var fs = require("fs");
fs.readdir('data',function(error, files) {
    if (error) {
        throw error;
    }
    console.log(files);
});

output:

[ 'capitals.txt', 'provinces.txt' ]

Child Process

The child_process module allows you to communicate with other applications on your system by executing external processes in your environment. There are four kinds of child processes; exec(), spawn(), execFile(), fork(). I will be covering exec() and spawn() here. If a child process will execute once, use exec() function. For example the “cal” command on terminal prints the current month’s calendar in the terminal. The command is executed once, prints a result and that’s it. If a child process would be running for a long time and printing output several times, use spawn() function. An example would be:

tail -f error_log

This command would keep running as long as apache is running and it would continue to print new entries in the error_log as they come.

The following code opens a page in your default browser:

var cp = require("child_process").exec
exec("open http://google.com");

The following code runs a command in the terminal and displays its output:

var cp = require("child_process").exec;
cp("node -v", function(err, stdout) {
    if (err) {
        throw err;
    }
    console.log("Node version ");
    console.log(stdout);
});

This code runs the command “node -v” on the command line. This command returns the version of node installed on your system. This stdout output is then displayed by this program.

Create Server

The following code creates a server and assign a port.

var http = require('http');

http.createServer(function (req, res) {
    res.writeHead(200, {'Content-Type': 'text/plain'});
    res.end('Your node server is running');
}).listen(8282);

Simply run the code and open http://localhost:8282 in your browser.