Skip to content

util: add `options` to util.promisify()

This PR adds an optional second argument to util.promisify().

options.resolveArray solves a problem with callbacks taking more than one non-error argument: Promise can't be resolved with more than one value, so further results are lost. With this option, Promise is resolved with an array of all non-error arguments. For internal methods, this problem is solved with appropriate kCustomPromisifiedSymbol and kCustomPromisifyArgsSymbol properties. But util.promisify() is a part of public API, and this approach is not applicable to userland.

options.callbackPosition solves a problem with functions not having callback-last signature. Most notably, a function can't have callback as last argument when we want to be able to omit last arguments or use ...rest:

  • We can't do util.promisify((foo, optionalBar, cb) => cb(!foo, optionalBar))('fooValue', callbackFn) and expect optionalBar to be magically undefined or arguments.length to be magically adjusted.
  • We can't do (foo, ...optionalArgs, cb) => {} at all.

With that new option, we'll be able to promisify (foo, cb, optionalBar = 'defaultBar', ...restArgs) => {}.

Example:

'use strict';
const { promisify } = require('node:util');

const fn = (foo, bar, baz, cb) => void cb(baz !== undefined, foo, bar, baz);
const fnOpt = (cb, ...args) => void cb(args[2] !== undefined, ...args);

// old
const Pfn = promisify(fn);
(async () => {
  console.log(await Pfn(1, 2, undefined)); // 1
  console.log(await Pfn(1, 2)); // TypeError: cb is not a function
})().catch(err => console.error('caught:', err));

// new
const PfnArr = promisify(fn, { resolveArray: true }); // callbackPosition: 3
const PfnOpt = promisify(fnOpt, { resolveArray: true, callbackPosition: 0 });
(async () => {
  console.log(await PfnArr(1, 2, undefined)); // [ 1, 2, undefined ]
  console.log(await PfnOpt(1, 2)); // [ 1, 2 ]
  console.log(await PfnArr(1, 2, 3)); // caught: true (desired truthy error)
})().catch(err => console.error('caught:', err));

Documentation might require some rewording.

Merge request reports

Loading