Enough Node for Building a Basic Command Line Script

In the last post we covered the very basics of what Node is and how to install it but now it’s time to write something that’s potentially useful. though most would jump directly into building a website, I want to do a little on the command line to explain a few concepts about node and in the process point you in the direction of how to make some useful tools for yourself.

Reading a File, Sync versus Async

As was mentioned in the previous post, a Node process is single-threaded and hands I/O-heavy tasks to other processes so that it can process further requests. In other words, instead of handling all I/O requests synchronously, the best way to generally use Node is to handle requests asynchronously. Though this is usually the behavior you want, you can break this rule. When creating a website this will almost always be a bad idea but when creating a command-line tool, it’s fine to force everything to be synchronous.

Let’s see this in action. Have you ever had to do some processing on a text file? Maybe you wrote some ad-hoc code to parse through a CSV file or had to convert some plain text to HTML. It’s something most programmers have to do everyone once in a while, so let’s create a simple script to do that. Let’s say we have a text file like the following.


Name: Bob Smith
Title: Chief Excel Master
Notes: Drinks way too much Pepsi but has good taste in steaks.

We want to turn this into HTML, with each line a paragraph and the label text on the left of each line in bold. Here is a script for doing that.


var fs = require('fs'); //#1
var contents = fs.readFileSync('textfile.txt', { encoding: 'utf8' }); //#2
var lines = contents.split('\n'); //#3
var html = '';
lines.forEach(function(line) {
    var segments = line.split(':');
    html += '<p><b>' 
        + segments[0]
        + '</b>'
        + segments[1]
        + '</p>\n'
});
console.log(html);

The results are as follows:


<p><b>Name</b> Bob Smith</p>
<p><b>Title</b> Chief Excel Master</p>
<p><b>Notes</b> Drinks way too much Pepsi but has good taste in steaks.</p>

Now let’s go back and discuss readFileSync. If you look at the documentation for the fs module on the Node website, you’ll notice that most of the methods come in pairs. In the case of readFileSync, it has a corresponding method without the word “Sync” on the end that takes the same arguments plus a callback. If you look at the documentation for the FileSystem module of Node you will probably notice that almost every method on the module comes in a pairs of async and sync methods (e.g. open and openSync, mkdir and mkdirSync).

Many other languages like C# (I have spent most of my professional career writing in this language) and their supporting frameworks take a very different approach. C# has always supported multi-threading (so there has always been support for writing synchronous and asynchronous code) and the async/await features of C# that were recently added are quite fantastic. But despite that, synchronous is still the default. As an example if you look at the C# WebClient class you will notice there there are a number of methods that come in synchronous/asynchronous pairs but the naming pattern is different than what you find in Node. In C#, the synchronous name is the default where the asynchronous name is the exception (e.g. DownloadFile and DownloadFileAsync, OpenRead and OpenReadAsync).

I spent that time talking about C# to make a point, which is that in Node asynchronous is the default mindset . So let’s take our read file example and re-implement it using the asynchronous version of the readFile API so we can see how we would more often use Node APIs.


var fs = require('fs');
var callback = function(err, contents) {
    var lines = contents.split('\n');
    var html = '';
    lines.forEach(function(line) {
        var segments = line.split(':');
        html += '<p><b>' 
            + segments[0]
            + '</b>'
            + segments[1]
            + '</p>\n'
    });
    console.log(html);
}
fs.readFile('textfile.txt', { encoding: 'utf8' }, callback);

There are only two important changes here. First is the change of the method name from readFileSync to readFile. The second is that all the processing of the text file was moved into a callback function that executes when the contents of the file have been read from disk and are available for use. Note that readFile doesn’t return the contents of the file. The reason why is because the file process has been delegated elsewhere and node will immediately continue processing. But when the file read operation is finished, the callback will be fired and the data will be passed as the second parameter of the callback.

What We Covered and What’s Next

In this post we covered a few basic but important things.

  1. You learned that you can create scripts that are runnable from the command line. This means you can use Node to create useful utilities or process files.
  2. You learned that Node is asynchronous by default. Though there is certainly a time for synchronous operations, even its naming patterns are trying to enforce the centrality of asynchronicity in the framework.

Next we jump into creating a website.

comments powered by Disqus