Using Q and Promises to Read from File with Node

Project Files

Click here to download the project files.

...

Also be sure to check out my latest course on Angular 2 using this coupon link: http://bit.ly/1SWkFxM

Using q is very easy. In this post we are going to use the defer method to create a deferred object which represents a value that will be resolved or rejected in the future. For example, when we read from file with Node asynchronously, if the operation is successful, then you can resolve the object with the content of the file, otherwise you can reject it and catch it in your code. Let's gat started.

Make a folder on your desktop, navigate to it and start a package.json file and accept all the defaults:

mkdir ~/Desktop/q-read && cd $_ && npm init

Install q:

npm i q -S # -S means as a production dependency

Make a dummy file:

touch dummy.txt
echo hello > dummy.txt

Make the main.js file that will contain the main code:

touch main.js

Now we are ready to fill the main.js file.

First, let's just read the file with vanilla Node:

var fs = require('fs');
fs.readFile('./dummy.txt', 'utf-8', function (err, data) {
  if (err) {return console.log(err);}
  console.log(data);
});

Here we are just reading the content of the dummy.txt file in utf-8 format, and just logging the content to the console. If you run the code with node main.js, you should get the following output:

> node main.js 
hello

Now, let's make things interesting. We are going to create a function called read that returns a promise:

var q = require('q');
var read = function () {
  var deferred = q.defer();
  deferred.resolve('done');
  return deferred.promise;
};

If you look at the code, first we load q. Then, we create a function and in the function we first create a deferred object. And we just resolve it with a dummy value called 'done'. And at the end we return the promise property of deferred.

Now, let's see how we can use the read function. So, obviously we are going to call the function first:

read()

When we call read it will return a promise. The promise has a method called then which can be used to access the resolved value:

read().then();

Now the then method takes a function, and the resolved value will be passed to the function as a parameter:

read().then(function doSomething(resolvedData) {});

And inside the function we can do whatever we want with the data:

read().then(function doSomething(resolvedData) {
	console.log(resolvedData);
});

This will log done to the console, because that is the value that we resolved. Now let's see how we can apply the same principle to the fs.readFile method.

var fs = require('fs');
var q = require('q');
var read = function () {
  var deferred = q.defer();
  fs.readFile('./dummy.txt', 'utf-8', function (err, data) {
    if (err) {deferred.reject(err)}
    else { deferred.resolve(data) }
  });
  return deferred.promise;
};

read().then(function (content) {
  console.log(content);
}).catch(function (err) {
  console.log(err);
}).finally(function () {
  console.log('Read is done.');
});

If you look at the code, you can see that we are using the same principle. There are a couple of new things, so let's go over them.

In the body of the function, we check for error, if an error happens we reject the promise with the err. Otherwise, we resolved the promise with the content of the file. Now, when we call the read function, we can grab the resolved value in the then block. But if there is an error, we will catch that in the catch block. And at the end, regardless of what happened, we will log to the console in the finally block.

And that's it! As an exercise, you can try implementing the fs.writeFile method as well, the principles are the same.