Promises – Part 3 – Using the Q library

Although promises are going to be a part of ES6 and thus a part of the language going forward, the first way I ever heard of using promises in JavaScript was the library Q (link here).

Q has been around since 2009 as a way to handle promises in JavaScript and has familiar methods to the ones outlined in the previous sections on promises. It’s quite small in size (8.5kb minified) and very powerful in terms of its ability to handle promises. It also has specific methods to handle node functions (which is very handy in my current job which uses a full node.js backend).

Here are a few of the different methods in the Q library that can be useful when dealing with different situations:

Q.all([promise1(), promise2()])

Q.all() can be used to take a group of promises and return them all as a single promise. This means that you can have multiple asynchronous operations and without chaining, write code that will run only once all the promises inside the array have been resolved. So to illustrate this further, once promise1() and promise2() have been resolved, you could immediately add:

.then(function(results) { //code })

In this case, the different values returned will be stored in an array in the .then() method (in the above example, the array is the results parameter).

Another cool trick when handling the results of the Q.all() method call instead of using.then() is by using .spread(). This method allows you to spread the different results of the promises within the array across different parameters within the follow-up function, like so:

Q.all([promise1(), promise2()])
.spread([result1, result2], function(result1, result2) { //code })

This might seem a little bit like overkill but if you think about it when you’ve got a much larger array, it can help keep your code clear and concise when dealing with the different results.

There are a huge amount of other useful features in Q that I could go over but then this post will basically mirror the documentation. I do however, want to look a little bit more at some of the cooler node-related functions available within Q.

In core node, asynchronous functions return a callback rather than a promise, take for instance the fs.readFile() method:

fs.readFile('./file.txt', function read(err, data) { //code })

With Q, you can target the readFile method and ‘denodeify’ it which creates a promise wrapper and makes it return a promise, as opposed to a callback. Denodeifying can be done like this:

var fs_readFile = Q.denodeify(fs.readFile)

Now fs_readFile can be used as a function that takes the same arguments as fs.readFile() (a filename) and it will return a promise:

var promise = fs_readFile('./file.txt')

And that promise can be used just like any other promise we’ve become used to!

promise.then(function(result, err) { //code })

.denodeify() is most useful if you’re going to be using a node function more than once so you can call it again in different places. An alternative to this method is to use .nfcall() which can be used for individual cases and turning a callback style function into one which returns a promise:

return Q.nfcall(fs.readFile, './file.txt')

Sometimes however when using .nfcall() on a method, you can run into the issue of unbinding the method from it’s original owner. Luckily, Q has the .ninvoke() method to handle this without causing the binding issues, so if we were dealing with parent.method() it would be written as:

Q.ninvoke(parent, "method", arguments)

In case you were wondering, the n in the previous functions stands for node, and nf stands for node function.

Again, there are a lot more complex situations that Q can handle in regards to promises, but this post has just listed some of the more common ones. Hopefully this has been helpful and in my next post I’m going to move away from promises and into generator functions!

Thanks for reading, if you’ve got any comments, please leave them below.


Further Reading:


3 thoughts on “Promises – Part 3 – Using the Q library

Leave a Reply

Fill in your details below or click an icon to log in: Logo

You are commenting using your account. Log Out /  Change )

Google photo

You are commenting using your Google account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s