util.promisify does not work as expected with object methods

  • Version: 12.11.1 and 13.1.0
  • Platform: Linux *** 4.15.0-66-generic Deprecate domains #75-Ubuntu SMP Tue Oct 1 05:24:09 UTC 2019 x86_64 x86_64 x86_64 GNU/Linux
  • Subsystem: util

Hi all

I'm having an issue with util.promisify, trying to apply it to an object method, as follow

const net = require('net')
const util = require('util')

async function start () {
  try {
    const server = net.createServer()
    const listen = util.promisify(server.listen)
    await listen(9123)
    console.log('started')
  } catch (error) {
    console.error(error)
  }
}

start()

output is

TypeError: Cannot read property '_handle' of undefined
    at Server.listen (net.js:1383:12)
    at internal/util.js:277:30
    at new Promise (<anonymous>)
    at internal/util.js:276:12
    at start (/home/simone/Desktop/util-promisify.js:8:11)
    at Object.<anonymous> (/home/simone/Desktop/util-promisify.js:15:1)
    at Module._compile (internal/modules/cjs/loader.js:945:30)
    at Object.Module._extensions..js (internal/modules/cjs/loader.js:962:10)
    at Module.load (internal/modules/cjs/loader.js:798:32)
    at Function.Module._load (internal/modules/cjs/loader.js:711:12)

because in net.js:1383 there is

while util.promisify do

original.call(this, ...args, (err, ...values) => {

so this at execution of listen function is no more its own instance, but a new context.

Reading the documentation, this is not reported, so I'm opening this issue - that I suppose to be a bug.

In my opinion, a possible solution could be adding an optional arg instance to util.promisify, like

util.promisify(original, [instance])

then, after checked that instance is an object and instance[original] exists, could be

original.call(instance || this, ...args, (err, ...values) => {

it could be called as

util.promisify(server.listen, server)

and works as aspected.

If you agree with this solution, I'd be glad to do that.