2

I am using async.parallel to run 2 functions at once, which are run from a static function on a mongoose model. As you can see, I can this this to access the model and it's functions in this code (the model has a static function called verifyParent):

async.parallel([
      async.apply(content, {slug: slug}),
      async.apply(this.verifyParent, req.body.reply),
    ], (err, result) => {
          //results
});

But in the this.verifyParent function, if I try to use this, it's equal to my express app, and not the mongoose model. I beleive async.apply is doing this, and I can't figure out how to make it keep the this value it would normally have.

In verifyParent, I'm trying to query mongodb. When I run this.findOne(), it says it's not a function, and looking at this seems to indicate it's set the app, not to the model.

鄭脈龍
  • 336
  • 1
  • 10
stackers
  • 2,701
  • 4
  • 34
  • 66

3 Answers3

1

From your question, this is the model.

then you should change code to

var model = this;
var verify = function(reply) {
  model.verifyParent(reply);
};
async.parallel([
  async.apply(content, {slug: slug}),
  async.apply(verify, req.body.reply),
], (err, result) => {
      //results
});

Because this keyword is context based. See Function context for more.

Anurag Awasthi
  • 6,115
  • 2
  • 18
  • 32
鄭脈龍
  • 336
  • 1
  • 10
  • Sorry, i edited your answer instead of mine. Removed my edit. – Anurag Awasthi Jul 19 '19 at 09:03
  • @nrgwsth I found his problem and let him to explore himself. I feel really _sad_ that he awarded your answer. ;( PS: bind() returns a functon, for better coding habbit, it should be extracted to local variable. (which is also what I try to show him) – 鄭脈龍 Jul 20 '19 at 01:14
1

You can just bind the function to current context like this,

async.parallel([
      async.apply(content, {slug: slug}),
      async.apply(this.verifyParent.bind(this), req.body.reply),
    ], (err, result) => {
          //results
});

This is the function definition of async.apply, which seems like it calls the passed function with passed arguments, that's why this gets set to parent scope which is express app.

So basically what is happening is this,

function apply(fn) {
  return fn();
}

var model = {
  prop: "world",
  verifyParent: function () {
    console.log("hello", this.prop)
  }
}

// model context is lost.
apply(model.verifyParent)

// bind to model explicitly.
apply(model.verifyParent.bind(model))
Anurag Awasthi
  • 6,115
  • 2
  • 18
  • 32
0

This can be done in the following ways:

Using arrow functions:

async.parallel([
      async.apply(content, {slug: slug}),
      async.apply(() => this.verifyParent, req.body.reply),
    ], (err, result) => {
          //results
});

Using hard binding:

...
function boundedVerifyParent() {
   return this.verifyParent.call(this)
}
...
async.apply(this.boundedVerifyParent, req.body.reply),
...

Or using bind method:

...
async.apply(this.verifyParent.bind(this), req.body.reply),
...
Andrei Todorut
  • 4,260
  • 2
  • 17
  • 28