The process object is globally available to every node module. It contains functionalities which allow us to interact with current process in the system.
The Process object also provides information about the runtime environment. In addition, standard input/output (I/O) occurs through process, we can also gracefully terminate a Node application and we can even signal when the Node event loop (We will discuss this) has finished a cycle.
This is also useful for building command line applications as we can capture all user parameters passed to the program which it has been invoked from the terminal.
The user provided parameters are available in the process.argv variable.
Let us create a small terminal program that passes a message to the module. Create a file called greeting.js
console.log("Total Arguments: ", process.argv.length);console.log(process.argv);
The above program when executed from the command prompt/terminal will output the below details.
Invoking the above program with two parameters “hello” and “world” results in the above output. The first argument is the node process itself, followed by the file/module to be executed.
Understanding Node environment with Process object
Let us now explore the Node environment by using Process along with the -p command line option with Node.
For instance, to check out the process.version, type the following:
node -p "process.versions"
Take a peek at the output from the above command
NOTE: The double quote works on all platform. The single quote may not work in windows. It will even work without giving any quotes.
The process.env property is a great way to peek into the development/production environment.
node -p "process.env"
The output is too long to be displayed here but I assume you got the idea.
You can even dig into the details of the objects as shown below.
process -p "process.release.lts"
The output of the above command may differ depending on what we have installed.
For me the output is shown below.
But in case you have both LTS and Current environments, the output may defer.
Process I/O functions: Standard Streams
Standard streams are pre-established communication channels between an application and its environment. They consist of a standard input (stdin), standard output (stdout), and standard error (stderr).
Process I/O functions are inherited from EventEmitter (we will cover this shortly).
In a Node application, these channels provide communication between the Node application and the terminal. In short they are the means via which we can communicate with the application.
We can receive input from the stdin and write the output to stdout and stderr channels.
NOTE: You can’t close these streams or end them within the application.
TIP: Set the encoding for the stream before working with it.
Reading and writing to standard I/O
Whenever we need to get data into and out of a program, one useful technique is to use the process object to read and write to standard I/O streams.
Problem: How to pipe data to and from a Node program.
Solution: Use process.stdout and process.stdin.
Discussion:
The process.stdout object is a writable stream to stdout and every node program has access to it.
Example: An example program to transform input stream into uppercase data.
/* USAGE: cat file.txt | node uppercase-pipe.js*/// Tell the stream we're ready to start readingprocess.stdin.resume();process.stdin.setEncoding('utf8');process.stdin.on('data', function (data){process.stdout.write(data.toUpperCase());});
The output of the above program is shown below. Windows users please use git bash/git shell to execute the program.
In the above screenshot, we are piping the output of cat to our program which converts the text to uppercase.
You can pass in any file as input to this, in this the program itself is the input.
How does it work?
Everytime a chunk of text is read from the input stream, it’ll be transformed to uppercase and then written to the stdout.
Logging Messages
Lets use some logging feature of console object and see the behaviour.
let data = "An important message";let from = {name: "admin"};// A space is automatically added after':'console.log('Notice:', from);console.log('Hello %s:', from);console.error('Error: ', from);
Lets’ execute the program as shown below
$ node consolelog.js 2>error-log.txt
Let’s now see the output and understand the redirection to error log that is happening.
You will see the console.log getting logged here, but not the console.error. The reason is we indicated with the 2>error-log.txt to redirect all errors to the file.
If you check the file error-log.txt, you should see the below output.
NOTE: Standard streams come in three flavors: stdin, stdout and stderr. In unix based system these are referred to with numbers.
0 — is used for standard input1 — is used for standard output2 — is used for standard error
The same also applies to windows as well.
So, in the above execution 2> error-file.txt, the 2 refers to the error stream. This means we can redirect errors to a log file without having to open files within our Node program, or using a specific logging module.
Benchmarking a Node
One of the useful skills to have is to know how to time your application using built in language features.
Problem: Benchmark a slow operation
Solution: Use console.time() and console.timeEnd()
Discussion
Using console.time(‘label’) records the current time in milliseconds, and then later calling console.timeEnd(‘label’) displays the duration from that point.
NOTE: The time in milliseconds will be automatically printed alongside the label.
Example
// BEGINNING OF PROGRAMlet fs = require('fs');let args = {'-h': commandUsage,'-r': readFile};function commandUsage() {console.log(args);}function readFile(file) {if (file && file.length) {console.log('Reading: ', file);console.time('read'); // START TIMINGlet stream = fs.createReadStream(file);stream.on('end', function () {console.log("\n");console.timeEnd('read'); // END TIMING});// OUTPUT to consolestream.pipe(process.stdout);} else {console.error('Please provide a file with the -r option');process.exit(1);}}let flag = process.argv[2];let fileName = process.argv[3];if (!flag) {console.log("Usage: filereader-bm [-h/-r] [filename] \n\n");process.exit(1); // non-zero menas an error occured}switch(flag) {case '-h':commandUsage();break;case '-r':readFile(fileName);break;}// END OF PROGRAM
Lets execute as node filereader-bm.js -r filereader-bm.js and see the output. The above command execution times how long it takes to read filereader-bm.js.
The output will be the contents of the file followed by the time. The extract of the content is shown below.
TIP: We can use several console.time with different lables to time different even nested portion of the code.
NOTE: We will look into file handling functions in later part of this article.