Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to set the context of the `this` inside a then callback on a promise

When I call resolve() on a Promise, the scope which the function inside the then() is binded to window.

There's any way to set the context of the this like using the Function.apply method?

function Point(){
  var that = this;
  
  var _x = 0;
  
  this.setX = function(x){
    return new Promise((resolve, reject)=>{
        setTimeout(()=>{
            _x = x;
            resolve.apply(that); //<== set this
        }, 1000);
    });
  }

  this.getX = function(){
    return _x;
  }
}

var p = new Point();
p.setX(10).then(function(){
  console.log(this.getX()); //this === `window`
});

EDIT:

Elaborating, with synchronous code you can do method chaining, by simply returning the same object over and over.

//this pattern
obj.method1();
obj.method2();
...


//becomes this pattern
obj.method1(10).method2(11) ...

Implementation of chaining

method1 = function(x){
    return this;
}

When it comes to assync, you can still do the same thing with callbacks

obj.method1(10, function(){ this.method2(11, function(){ ...

Implementation with callbacks

method1 = function(x, cb){
    cb.apply(this);
}

I don't get it why would someone bind the"receiver" function to window, it doesn't make sense to me, as promises are supposed to be analogous to synchronous calls.

like image 407
Vitim.us Avatar asked Oct 18 '22 18:10

Vitim.us


1 Answers

Option 1:

You can pass the instance into the resolve function. Then reference it via the callback as the first argument.

function Point() {
  var that = this;

  var _x = 0;

  this.setX = function(x) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        _x = x;
        resolve(that); //<== set this
      }, 1000);
    });
  }

  this.getX = function() {
    return _x;
  }
}

var p = new Point();
p.setX(10).then(function(scope) {
  console.log(scope.getX());
});

Option 2:

You can bind the scope of the callback:

var p = new Point();
p.setX(10).then(function () {
    console.log(this.getX()); //this === `window`
}.bind(p)); // bind the scope here

function Point() {
  var that = this;

  var _x = 0;

  this.setX = function(x) {
    return new Promise((resolve, reject) => {
      setTimeout(() => {
        _x = x;
        resolve.apply(that); //<== set this
      }, 1000);
    });
  };

  this.getX = function() {
    return _x;
  }
}

var p = new Point();
p.setX(10).then(function() {
  console.log(this.getX()); //this === instance of Point
}.bind(p));
like image 65
KevBot Avatar answered Oct 20 '22 09:10

KevBot