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:
Module | Description |
---|---|
assert | used for unit testing |
buffer | for handling binary data |
crypto | for openssl |
events | for event handling |
fs | file handling |
http | make Node.js act as an HTTP server |
https | make Node.js act as an HTTPS server |
net | create clients and servers |
os | gives info about the os |
path | handling file paths |
querystring | handle url querystring |
readline | handle readable streams |
stream | handle streaming data |
timers | timing functions like counting milliseconds |
tls | for implementing TLS and SSL protocols |
url | parsing URL strings |
util | utility functions |
zlib | To 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.