Quick Dig: util.promisify in Node.js
A quick (but hopefully thorough) look at Node’s newest feature

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.