codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

Follow publication

Quick Dig: util.promisify in Node.js

Brian Lee
codeburst
Published in
4 min readJun 27, 2017

--

(I admit, this is the most cliched lead image I’ve ever used.)

When the latest update to Node.js version 8 was released earlier this month, the main source of excitement for the community seemed to focus around the release of NPM version 5 which aims to fix the speed issues that lead to the rise of tools such as Yarn. There weren’t that many feature additions in the breaking update other than the addition of promisify in the util library. I personally thought this was a cool (albeit not exactly groundbreaking) feature and wanted to write this post sooner, but decided to wait for the @types/node update. (As I noted previously, since types are commonly maintained as open source projects, it takes some time for new features to be reflected on the definitions.)

Usage Example

promisify, as the name implies, is a method that generates promise functions; this is meant as a convenience wrapper for methods that use callback functions for asynchronous programming. Prior to promises, callbacks were the predominant method of asynchronous programming in JavaScript; functions were passed directly to methods as “instructions” to be invoked once the asynchronous computation was complete.

Fair or not, the callback style has been a source of plenty of complaints, as popularized by the term “callback hell”. The stacking indentations are definitely an eyesore and, more importantly, are often blamed for developer confusion. Promises, added officially in ES2015, can alleviate this problem by allowing subsequent actions to be chained using .then() or .catch(). As promises gain mainstream acceptance, it makes sense for Node to incorporate ways that allow its many libraries to be used in promise style without having to rewrite its libraries.

As an example, here’s the popular request package:

As the request() function is invoked, it requires a string (url) and a function, which is the callback to be invoked later.

We can use promisify to generate promises.

Diving into Source Codes

We can look at Node’s source codes to figure out exactly what is going on with this new feature. In /lib/util.js, exports.promisify points to a method in the internalUtil module, imported from internal/util.

Here is the relevant code excerpt from /lib/internal/util.js:

Lines 13–16 check for argument type. Lines 18–28 check for any values associated with a certain symbol, which we will examine further below. The main functionality of this method comes from lines 34–60: especially noteworthy is function fn() on lines 34–53 which is the main return type for the promisify method. Within this function, a promise is created, the original function passed in is invoked inside a try block (line 37) where the arguments supplied to the promisified function is submitted with a callback. Within this callback, if the asynchronous function returns an error or is caught in the catch block, the promise is rejected; otherwise it is fulfilled either with a single value that is returned (lines 45–46) or an object containing key-value pairs of all returned data (lines 40–44).

Lines 1 and 5 suggest that the handling of promises is done using the C++ bindings; the bindings are available in /src directory. Since this is not within the scope of this article, we’ll stop at noting that Node internally creates and resolves promises created through a promisified method.

Important to note here is that promisify assumes the callback accepted by the initial method will contain an error parameter as the first parameter. This is an accepted pattern for Node and many packages (not to mention all asynchronous methods in the included modules) implement this as a default. That said, using promisify on a method which does not implement this style of callbacks will result in wrong code since anytime the first parameter is not null or undefined, the promise will reject even in successful computations.

Custom Promises

Let’s look at lines 9–10; these lines define references to symbols. The symbol in line 9 is used in lines 18–28 where a conditional checks if there are any values associated with the symbol used as a key.

Symbols are a recent (ES2015) addition to JavaScript. Its exact usage varies in context but for the moment it is easiest to understand it as an invisible layer that contains instructions for the runtime. The full extend of its behaviors is, again, out of scope for this post so we will focus on the usage specific to promisify.

As we noted above, not all Node packages and libraries have the error-first callback defined. Sometimes this is an oversight, but often enough it is out of necessity and limitations of design. For these packages where the callback function is irregular, promisify provides a way to specify the behaviors of the promisified function. All we* need to do is retrieve the symbol reference fromutil.promisify.custom and define it as a property of the function whose value is the custom promisified function. Node will return exactly this function regardless of the actual operation of the asynchronous computation.

*By “we”, I really only mean a very small number of people. Likely applicable for anyone maintaining an npm package written before promises were widely available, which I imagine is an increasingly small crowd.

As of writing (June 26, 2017), the @types/node definition is missing definitions for util.promisify.custom, as well as util.inspect.custom. There is a decent possibility I work towards a pull request pertaining to this problem relatively soon.

For an existing example of this feature, see child_process.exec; the relevant parts are highlighted.

What’s the Next New Feature?

Callbackify, of course!

This is not exactly a joke. As of writing, a pull request for util.callbackify has been merged into the master branch, which suggests it should be available in the next round of updates.

Sign up to discover human stories that deepen your understanding of the world.

Free

Distraction-free reading. No ads.

Organize your knowledge with lists and highlights.

Tell your story. Find your audience.

Membership

Read member-only stories

Support writers you read most

Earn money for your writing

Listen to audio narrations

Read offline with the Medium app

--

--

Published in codeburst

Bursts of code to power through your day. Web Development articles, tutorials, and news.

No responses yet

Write a response