Dev1ce
Dev1ce

Reputation: 5954

How to use util.promisify and .bind functions in NodeJs?

I am migrating a code base written in Node v6.10 to v10.15.3,
I wish to use the async / await style and util library to avoid the callback hell my code has,
I am able to convert the functions into the new async/await style and use the util library functionality as well.

Someone highly recomended me to chain the .bind function to the util.promisify() function,

I understand that the .bind() is used for variable/object scope.
But is it really necessary to do the .bind after promisifying using the util lib?

Following is my sample code -

let fs   = require('fs');
let util = require('util');

let test = async () => {

    let keyPath = 'someFile.txt';

    //This works
    const fsReadFile = util.promisify(fs.readFile);

    //This also works
    //const fsReadFile = util.promisify(fs.readFile).bind(this);

    //This also works
    //const fsReadFile = util.promisify(fs.readFile).bind(fs);

    var fileContent  = await fsReadFile(keyPath, 'utf8');
    console.log(fileContent);
};

test();

I followed the following sites for the implementation -

1. util implementation -
https://medium.com/@suyashmohan/util-promisify-in-node-js-v8-d07ef4ea8c53

2. understand bind function -
a) https://blog.cloudboost.io/nodejs-bind-function-e5d33ea081f0
b) Use of the JavaScript 'bind' method

Unsure if there are the usecases -
1. https://github.com/nodejs/node/issues/13338
2. Function works, but fails when util.promisify() used?

enter image description here

Upvotes: 14

Views: 9816

Answers (3)

Vitaliy Markitanov
Vitaliy Markitanov

Reputation: 2448

Good explanation why you may need .bind() is on nodejs doc site, here: https://nodejs.org/api/util.html#utilpromisifyoriginal

... Using promisify() on class methods or other methods that use this may not work as expected unless handled specially:

const util = require('node:util');

class Foo {
  constructor() {
    this.a = 42;
  }

  bar(callback) {
    callback(null, this.a);
  }
}

const foo = new Foo();

const naiveBar = util.promisify(foo.bar);

// TypeError: Cannot read property 'a' of undefined
// naiveBar().then(a => console.log(a));

naiveBar.call(foo).then((a) => console.log(a)); // '42'

const bindBar = naiveBar.bind(foo);
bindBar().then((a) => console.log(a)); // '42'

Upvotes: 2

bendytree
bendytree

Reputation: 13629

util.promisify doesn't have a binding argument. So if you need to bind the context, do this:

const util = require('util');
const run = util.promisify(thing.run).bind(thing);

Source

Upvotes: 15

Danielo515
Danielo515

Reputation: 7161

No, in this case it is not needed. If you take a look at readFile implementation it does not make use of this at any moment:

https://github.com/nodejs/node/blob/master/lib/fs.js#L283

This means that the function will work if it loses its original context (the fs module) or if it is binded, it just does not matter. That's why all the examples you posted work without problems.

However there are many libraries that depends on its this context, hence they need binding. If someone is suggesting you to bind everything he/she probably does not have a big understanding of how javascript works, and they just prefer to bind everything because it will not hurt much if it is not needed (just a small performance hit that is not noticeable in any case).

My advice is to investigate each case separately or use libraries that uses promises natively.

Upvotes: 5

Related Questions