2

I have a situation where a method must call itself recursively, and asynchronously, via setImmediate.

The next code doesn't have any to do with the original, but the same "problem" arises: the "this" reference seems to be lost on the second call.

function A () {
   this.some_message = 'Index is: ';
}

A.prototype.someMethod = function (index) {
  console.log(`${this.some_message} ${index}`);
  setImmediate(this.someMethod, index + 1);
}

I have the next output, in where "this.someMethod", at some point, stops being a function, i'm not understanding it:

> new A().someMethod(1)
Index is:  1
undefined
> undefined 2
TypeError: "callback" argument must be a function
    at exports.setImmediate (timers.js:664:11)
    at Immediate.A.someMethod (repl:3:1)
    at runCallback (timers.js:639:20)
    at tryOnImmediate (timers.js:610:5)
    at processImmediate [as _immediateCallback] (timers.js:582:5)
> 

I solved it by changing the last line of the method to:

setImmediate(this.someMethod.bind(this), index + 1);

But i don't understand why setImmediate behaves like that. Can anyone provide me some link about it? I will really appreciate any help. I've been a couple of hours trying to find the answer. Thanks in advance.

-- edit: An also, feel free to suggest a better title or redaction. I have a pretty poor english level.

Emilio Grisolía
  • 1,183
  • 1
  • 9
  • 16

1 Answers1

4

Any time you are using higher-order functions, you will lose the context. You have three options: store a ref to this in a closure, bind the function you pass around, or don't use this.

// using Function.prototype.bind
var foo = { value: 3 };
foo.method = function() { return this.value };

function doesAsync() {
  setImmediate(foo.method.bind(foo));
}

// using a closure
var bar = {
  value: 3,
  method: function() {
    var self = this;
    setImmediate(function() {
      alert(self.value);
    });
  }
};
Jared Smith
  • 19,721
  • 5
  • 45
  • 83
  • I always avoid the "this"... but this time, i can't.. heh. Thanks :) I've been missing the fact that setImmediate is executed from another context. – Emilio Grisolía Oct 24 '16 at 17:43
  • 1
    @EmilioGrisolía. Yup, and that will happen every time you pass a method as an argument unfortunately. I try to avoid `this` too, but I also write google maps apps for a living :) – Jared Smith Oct 24 '16 at 17:44