Node8’s util.promisify is so freakin’ awesome!

Written by jamesjefferyuk | Published 2017/09/27
Tech Story Tags: javascript | nodejs | react | asynchronous | async

TLDRvia the TL;DR App

In this guide you will learn how to use Node’s util.promisify to promisify your own functions. This utility function was included in NodeJS version 8. If you plan to follow along with this guide you’ll need to install the latest version. As an added bonus I also show you how to use promisify with await and async.

TLDR;

  • util.promisifyconverts a regular function into an async function, i.e. a function that returns a promise
  • The function passed to util.promisify must follow the NodeJS callback style. The function must pass a callback as the last parameter, and the callback must be the take the following parameters in the following order: (err, value) => { /* … */ }
  • Promisified functions can be used with await and async to help avoid messy promise chains and introduce a cleaner, saner, way to do asynchronous programming.

What does util.promisify do?

The official node documentation says:

Takes a function following the common Node.js callback style, i.e. taking a (err, value) => ... callback as the last argument, and returns a version that returns promises.

And …

promisify(original) assumes that original is a function taking a callback as its final argument in all cases, and the returned function will result in undefined behaviour if it does not.

So basically it’s a utility function that takes a regular function and converts it to a function that returns a promise/s.

The function passed to util.promisify has to follow a couple of conventions:

  1. The final parameter of the function passed to promisify must be a callback.
  2. The callback must follow Node’s callback style.

Here is an example of a valid function:

Note: For anyone unfamiliar with the syntax I’m using ES6. I also use the Airbnb style guide.

To demonstrate how util.promisify works lets start by creating a regular function that performs a task over a long period of time. We will then convert this function to a promise.

Creating a Regular Function

Below I have a function called wait. Its purpose is to make you wait for an unknown period of time:

For demonstration purposes I’ve wrote the function to wait for an unknown period of time. It does this by using setInterval to call an anonymous function every x number of seconds and compares the number to a set of values to decide whether to continue waiting, or to stop:

  • If the number is above 0.95 the function will stop running and the callback function will be called.
  • If the number is less than 0.01 an error will be passed to the callback function.
  • And finally, if the random number is within range a message will be printed to STDOUT.

NodeJS Callback Style

util.promisify expects a function that conforms to NodeJS’s callback style. To learn more about Node’s callback style read this article: The Node.js Way — Understanding Error-First Callbacks

In the wait function you will notice I used the callback is used in 2 different ways. When the random number was greater than 0.95 this is considered a success and the wait is over. Thus we can call the callback like so:

callback(null, ‘Congratulations, you have finished waiting.’);

Here I passed null to the first parameter. No error occurred. Nothing to report. Using the second parameter I pass some data that is made available in the callback, or promise chain.

When the wait function failed (in this case when the random number is below 0.01) an error message is passed to the first parameter. The second parameter is set to null.

callback(‘Could not wait any longer!’, null);

This follows Node’s callback style.

Usage

The function is called like so:

the function expects 2 parameters. The first is the number of milliseconds to wait before setInterval calls the callback function. The second parameter is a callback.

Notice how I’m checking for an error: if (err) throw new Error(err) … if err is null the callback continues. Otherwise an exception is thrown.

Test Running

Running the above code produces the following output on success:

… and the following output on error:

We confirm the function does as expected. Next we will turn it into a promise.

Promisify Regular Functions

Here’s where the magic happens.

Now we have an ordinary function I can demonstrate how to turn into a function that returns a promise. This is surprisingly easy …

That’s it. In 2 lines of code I converted the function to a promise. Line 7 to 9 show how to use the new promise. You will agree it’s much cleaner and easier to read.

Introducing Async and Await

Wait, we’re not finished yet. I’ve got some more juicy goodness to share with you. Node 8 also comes with async and await support. How freakin’ cool!

Instead of using promise chaining (which can get very messy very quickly) you can write your code in a normal procedural style like so:

No more promise chains :)

For more information on async/await I highly recommend the following article: https://blog.risingstack.com/mastering-async-await-in-nodejs/

😊

P.S. If you’re on Twitter give me a follow. I often write articles on software development, and security: https://twitter.com/JamesJefferyUK


Published by HackerNoon on 2017/09/27