6

I'm trying to write a class that has methods that return promises and promise chains. This attempt returns error from do_that()

I understand the problem with using 'this' which is why I used the self=this kludge, but I still get an error.

TypeError: Cannot read property 'name' of undefined.

In addition to the question, how do I fix this, is there a cleaner way to do this?

var Promise = require('bluebird');

    class myClass {

        constructor(name, pipeline) {
            this.name = name;
        }

        do_this() {
            var self = this;    // <-- yuck. Do I need this?
            return new Promise(function(resolve, reject) {
                setTimeout(function () { console.log("did this " + self.name);  resolve(self);  }, 1000);
            })
        }

        do_that() {
            var self = this;    // <-- yuck
            return new Promise(function(resolve, reject) {
                setTimeout(function () { console.log("did that " + self.name);  resolve(self);  }, 1000);
            })
        }

        do_both() {
            return this.do_this().then(this.do_that);
        }

    }

    new myClass("myobj").do_both();  // <-- TypeError: Cannot read property 'name' of undefined.
GroovyDotCom
  • 1,304
  • 2
  • 15
  • 29
  • 6
    That's NOT a duplication.... – Panthro Aug 12 '16 at 23:55
  • 1
    This is not a duplication! Don't think you read the question. – GroovyDotCom Feb 19 '17 at 14:47
  • It *is* a duplicate. It's just not about the function that you pass to `new Promise` and to `setTimeout` (where you used `self` correctly), it's about passing `this.do_that` as a callback to `then` (in `do_both`). – Bergi Dec 31 '17 at 15:46
  • 2
    For my money, the comment by Matt below regarding bindall() is the fully complete answer to my question. There is partial overlap with the other questions but it is not a duplicate which is why it has a different answer. – GroovyDotCom Dec 31 '17 at 19:20

1 Answers1

17

This is what Arrow Functions are for:

 do_that() {
        return new Promise((resolve, reject) => {
            setTimeout(() => { console.log("did that " + this.name);  resolve(this);  }, 1000);
        })
    }
Evan Davis
  • 35,493
  • 6
  • 50
  • 57
  • 7
    This partly answers the question. The other issue is `do_both` passes `this.do_that` to be called later unbounded. So either `return this.do_this().then(this.do_that.bind(this));` or `return this.do_this().then(x => this.do_that(x));` in that case – Matt Feb 11 '16 at 14:53
  • Thanks but still ugly. Can't I somehow retain the pretty Promise chain syntax dothis(obj).then(dothat) ? – GroovyDotCom Feb 11 '16 at 16:46
  • 2
    @GroovyDotCom if your primary goal is "pretty" code, JavaScript may be the wrong language for you. – Evan Davis Feb 11 '16 at 17:00
  • 6
    @GroovyDotCom you can bind your methods in the constructor: `this.do_that = this.do_that.bind(this);` - then you won't have to bind it anywhere else in the code. This pattern is common enough that utility libraries include functions like [`bindAll`](https://lodash.com/docs#bindAll) to make it easier. – Matt Feb 11 '16 at 17:05
  • 1
    Any pointers to explain why ES6 introduced Classes and didn't bind methods to "this" automatically? – GroovyDotCom Feb 12 '16 at 06:04
  • 4
    @GroovyDotCom it didn't introduce classes, it introduced the `class` keyword as sugar for the existing constructor pattern. It doesn't do anything new under the hood. – Evan Davis Feb 12 '16 at 16:12
  • I had a similar issue, this solution did the fix. Thanks for sharing @Mathletics – parpar Aug 30 '18 at 07:40