13

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

Dev1ce
  • 5,390
  • 17
  • 90
  • 150
  • 1
    I see no reason to use bind here at all. It just does not make sense. Bind is: 1. sign of bad code in ES6 imho. 2. Used to bind context which is totally unnecessary when using `fs` – Marek Urbanowicz May 15 '19 at 07:07
  • Would it be necessary if a custom function, which returns a callback is being promisified? I couldn't understand the reason I was told but, just understood it's necessary for some reason. – Dev1ce May 15 '19 at 09:09
  • no it is not necessary – Marek Urbanowicz May 15 '19 at 09:13
  • @MU updated the question, added some use case links, not sure if that is why. – Dev1ce May 15 '19 at 09:48
  • no needs of using `utils.promisify` since stripe api returns promises, at least for for `stripe` version `6.27.0` – The Reason May 15 '19 at 10:00
  • I ran into the same problem due to a recent update of the google sheets API that suddenly requires this context. `call` works and seems logical to me. What bothers me is that I could not find a documentation of this property of promises to be "call()"ed versus called just with "()" (without `this` context). – peschü Dec 18 '19 at 11:25

3 Answers3

12

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

bendytree
  • 13,095
  • 11
  • 75
  • 91
5

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.

Danielo515
  • 5,996
  • 4
  • 32
  • 66
1

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'
Vitaliy Markitanov
  • 2,205
  • 1
  • 24
  • 23