Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Accessing 'this' of an object inside promise callback (then)

I want to create an object in Javascript.

One of the methods should execute a promise chain. Each of the methods in the chain have to access a config variable that is a member of the object. The problem is, the this operator is changed in PromiseMethod2 and I can't access the config variable (It works correctly in PromiseMethod1).

Here's my code:

var SomeObject(config) {
    var that = this;
    that.config = config;
}

SomeObject.prototype.SomeMethod = function() {
    var that = this;

    that.PromiseMethod1()
      .then(that.PromiseMethod2)
      .catch(console.error);
    }

SomeObject.prototype.PromiseMethod1 = function() {
    var that = this;
    config = that.config;

    return SomePromise();
}

SomeObject.prototype.PromiseMethod2 = function(someParams) {
    var that = this;
    config = that.config;
    params = someParams;

    return SomePromise();
}


var someObject = new SomeObject(someConfig);
someObject.SomeMethod().then(function () {
    console.log('Done!');
}

I want to use the method delegate in the chain instead of just executing:

 that.PromiseMethod1().then(function(response) { return that.PromiseMethod2(that, response); };

I can't use the bind method because it looks like it gets rebinded when the callback is executed.

Is there a solution to this? Why's there a difference between PromiseMethod1 and PromiseMethod2?

like image 514
shudima Avatar asked Dec 20 '15 13:12

shudima


People also ask

How do you return from promise then?

Return valuereturns a value, the promise returned by then gets resolved with the returned value as its value. doesn't return anything, the promise returned by then gets resolved with an undefined value. throws an error, the promise returned by then gets rejected with the thrown error as its value.

What is callback in promise?

A callback function is passed as an argument to another function whereas Promise is something that is achieved or completed in the future. In JavaScript, a promise is an object and we use the promise constructor to initialize a promise.


1 Answers

My real recommendation is not to use this or new at all (and you can use Object.create if you still want inheritance):

var SomeObject = function(config) {
    return {
        PromiseMethod1: function(){
            return somePromise(config.foo);
        },
        PromiseMethod2: function(x){
            return someOtherPromise(config.bar, x);
        }
    }
}

var instance = SomeObject({config: true});
instance.PromiseMethod1().then(instance.PromiseMethod2);

Here I'm using closures, and their ability to enclose variables of their parent lexical scope, to my advantage. Rather than relying on JavaScript to magically inject a this into my function at run-time based on which object the function is called on, because as demonstrated by your problem, that doesn't always work.

However, I know that its an unconventional way to work, so if you'd rather stick with this, you'll need to use bind in order to tell JavaScript which magical this-value the function belongs to:

var SomeObject function(config) {
    this.config = config;
}

SomeObject.prototype.PromiseMethod1 = function(){
    return somePromise(this.config.foo);
}

SomeObject.prototype.PromiseMethod1 = function(x){
    return someOtherPromise(this.config.bar, x);
}

var instance = new SomeObject({config: true});
instance.PromiseMethod1().then(instance.PromiseMethod2.bind(instance)); //<- :(

In your example SomeMethod you're not actually using bind. You still need to bind because you're passing the function into .then(f), and the code which receives the function doesn't know anymore which object it should use for the this. Now look at my earlier recommended code again. There are no thisses in there, so those functions don't rely at all on which object they're being called on, you can pass them around as higher-order-functions as much as you want without ever having to bind or that = this. :)

like image 164
Avaq Avatar answered Oct 01 '22 09:10

Avaq