Node: Handling `Function.length` currently with `util.promisify`

Created on 16 Nov 2017  ยท  4Comments  ยท  Source: nodejs/node

  • Version: v9.2.0
  • Platform: Darwin 17.2.0 (MacOS)
  • Subsystem: util

Some code relay on the Function.length to detect how many arguments the function expect to handle.

For example:

const unlink = (file, cb) => fs.unlink(file, cb);
console.log(unlink.length); // 2

// Usage: (path, callback)
unlink('test.log', err => err && console.error(err));

Promisifying a function reduce the last callback arguments so I think that the length of the promisify function should be equal to 1. Currently it's 2:

const unlinkAsync = util.promisify(unlink);
console.log(unlinkAsync.length); // 2

// Usage: (path)
unlinkAsync('test.log').catch(err => console.error(err));
promises util

Most helpful comment

Case in point 1:

const defaultCallback = console.log.bind(console);
function myAsyncFunc(param1, param2, callback = defaultCallback) {
  // ...
}

myAsyncFunc.length === 2;

Case in point 2:

function myAsyncFunc(param1, param2, callback) {
  // ...
}

/*
โ–‘โ–‘โ–‘โ–‘โ–‘โ–„โ–„โ–„โ–„โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–„โ–„โ–„โ–„โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–€โ–€โ–„โ–‘โ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–’โ–’โ–’โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–„โ–ˆโ–ˆโ–€โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–„โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘
โ–‘โ–„โ–€โ–’โ–„โ–„โ–„โ–’โ–‘โ–ˆโ–€โ–€โ–€โ–€โ–„โ–„โ–ˆโ–‘โ–‘โ–‘โ–ˆโ–ˆโ–„โ–„โ–ˆโ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘
โ–ˆโ–‘โ–’โ–ˆโ–’โ–„โ–‘โ–€โ–„โ–„โ–„โ–€โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–‘โ–ˆ
โ–ˆโ–‘โ–’โ–ˆโ–‘โ–ˆโ–€โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–€โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–‘โ–‘โ–„โ–€โ–€โ–€โ–„โ–’โ–ˆ
โ–‘โ–ˆโ–‘โ–€โ–„โ–‘โ–ˆโ–„โ–‘โ–ˆโ–€โ–„โ–„โ–‘โ–€โ–‘โ–€โ–€โ–‘โ–„โ–„โ–€โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–ˆโ–‘
โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–€โ–„โ–€โ–ˆโ–„โ–„โ–‘โ–ˆโ–€โ–€โ–€โ–„โ–„โ–„โ–„โ–€โ–€โ–ˆโ–€โ–ˆโ–ˆโ–‘โ–ˆโ–‘โ–‘
โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–ˆโ–ˆโ–‘โ–‘โ–€โ–ˆโ–„โ–„โ–„โ–ˆโ–„โ–„โ–ˆโ–„โ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–ˆโ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–€โ–€โ–„โ–‘โ–ˆโ–‘โ–‘โ–‘โ–ˆโ–‘โ–ˆโ–€โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–ˆโ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–€โ–„โ–„โ–„โ–ˆโ–„โ–ˆโ–„โ–ˆโ–„โ–ˆโ–„โ–€โ–‘โ–‘โ–ˆโ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–„โ–‘โ–’โ–’โ–’โ–’โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–’โ–‘โ–‘โ–‘โ–ˆโ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–€โ–„โ–„โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–„โ–„โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘
*/
Object.defineProperty(myAsyncFunc, 'length', { value: 1 });

myAsyncFunc.length === 1;

All 4 comments

Iโ€™d say patches are welcome, but relying on fn.length is never going to be a 100ย % solution due to the way JS functions work.

Case in point 1:

const defaultCallback = console.log.bind(console);
function myAsyncFunc(param1, param2, callback = defaultCallback) {
  // ...
}

myAsyncFunc.length === 2;

Case in point 2:

function myAsyncFunc(param1, param2, callback) {
  // ...
}

/*
โ–‘โ–‘โ–‘โ–‘โ–‘โ–„โ–„โ–„โ–„โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–€โ–„โ–„โ–„โ–„โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–€โ–€โ–„โ–‘โ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–’โ–’โ–’โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–„โ–ˆโ–ˆโ–€โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–„โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘
โ–‘โ–„โ–€โ–’โ–„โ–„โ–„โ–’โ–‘โ–ˆโ–€โ–€โ–€โ–€โ–„โ–„โ–ˆโ–‘โ–‘โ–‘โ–ˆโ–ˆโ–„โ–„โ–ˆโ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘
โ–ˆโ–‘โ–’โ–ˆโ–’โ–„โ–‘โ–€โ–„โ–„โ–„โ–€โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–’โ–’โ–’โ–’โ–’โ–‘โ–ˆ
โ–ˆโ–‘โ–’โ–ˆโ–‘โ–ˆโ–€โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–€โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–‘โ–‘โ–„โ–€โ–€โ–€โ–„โ–’โ–ˆ
โ–‘โ–ˆโ–‘โ–€โ–„โ–‘โ–ˆโ–„โ–‘โ–ˆโ–€โ–„โ–„โ–‘โ–€โ–‘โ–€โ–€โ–‘โ–„โ–„โ–€โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–ˆโ–‘
โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–€โ–„โ–€โ–ˆโ–„โ–„โ–‘โ–ˆโ–€โ–€โ–€โ–„โ–„โ–„โ–„โ–€โ–€โ–ˆโ–€โ–ˆโ–ˆโ–‘โ–ˆโ–‘โ–‘
โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–ˆโ–ˆโ–‘โ–‘โ–€โ–ˆโ–„โ–„โ–„โ–ˆโ–„โ–„โ–ˆโ–„โ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–ˆโ–‘โ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘โ–‘โ–‘โ–€โ–€โ–„โ–‘โ–ˆโ–‘โ–‘โ–‘โ–ˆโ–‘โ–ˆโ–€โ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–ˆโ–‘โ–ˆโ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–€โ–„โ–„โ–„โ–ˆโ–„โ–ˆโ–„โ–ˆโ–„โ–ˆโ–„โ–€โ–‘โ–‘โ–ˆโ–‘โ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–„โ–‘โ–’โ–’โ–’โ–’โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–’โ–‘โ–‘โ–‘โ–ˆโ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–€โ–„โ–„โ–‘โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–’โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘
โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–€โ–„โ–„โ–„โ–„โ–„โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–‘โ–ˆโ–‘โ–‘
*/
Object.defineProperty(myAsyncFunc, 'length', { value: 1 });

myAsyncFunc.length === 1;

Should this stay open? I think there is little to do on our side. Any function could use the arguments object instead of predefined arguments as well. So relying on the length is really bad.

Doesn't look like it. I'll close this out.

Was this page helpful?
0 / 5 - 0 ratings