-1

I have a module like this.

somemodule.js

module.exports = {
  val: null,
  get: function() {
     finddata('/', function(resp) {
       this.val = resp
     }
  }
}

and is called like this:

var x = require('somemodule');
x.get();
x.get();

After the 1st get call, this x.val is not being set. Tried this as well which does not work:

module.exports = {
  val: null,
  get: function() {
     var that = this;
     finddata('/', function(resp) {
       that.val = resp
     }
  }
}

How do I set x.val?

Kris Molinari
  • 503
  • 6
  • 17
C B
  • 12,482
  • 5
  • 36
  • 48
  • Is `finddata` async? Are you sure its callback has been called? – Wiktor Zychla Jan 01 '17 at 18:32
  • It is async, and it is being called – C B Jan 01 '17 at 18:34
  • 2
    The first snippet won't work as intended because `this` keyword in the callback means the function itself instead of the whole object you want to export. I don't see anything wrong with the second approach so how did you check if 'x.val' is set or not? Can you do `console.log(that)` to see if it is set? – Nghia Tran Jan 01 '17 at 18:36
  • *"Tried this as well which does not work"* That will work. The problem is that you don't know when the async operation finished, so you don't know when to look at `x.val`. – Felix Kling Jan 01 '17 at 18:41
  • Could you share the relevant code for `finddata`? – thgaskell Jan 01 '17 at 20:52

2 Answers2

2

Your finddata is running asynchronously , it's getting called and returned back immediately to continue next line execution . That moment its not sure callback is executed or not . Once callback is executed then only value will be set . To make sure value is set and then after getting the value , you can use promises.

I have just taken two sample file a.js and b.js to explain how it works

a.js

module.exports = {
      val:null,
      get:function(){
          var that = this;
          return new Promise(function(resolve, reject) {
              that.finddata('/', function(resp){
                   that.val = resp;
                   resolve()
                 })
          });

      },
      finddata :function(path,callback){
          setTimeout(function() {
            console.log("Lets wait for some time");
            callback(10);
          }, 100)
      }
    }

b.js

var x = require('./a');
 x.get().then(function(){
       console.log(x.val)
 });

Output

Lets wait for some time

10
Sumeet Kumar Yadav
  • 11,912
  • 6
  • 43
  • 80
2

First of all, problem is not about requiring something and it is not related to scope. What is actually happening is, as already stated by others, finddata is asynchronous function meaning that you don't know at what time in future callback function (resp) {...} will be invoked and when val be something other than null. To tackle this you need either to pass additional callback to get function, or to return a promise from get function. Cleaner approach would be to return Promise from get function.

x.get()
.then(() => {
  // val is ready
})

or

x.get(() => {
  // val is ready
})

Another problem that you have is that you are not taking into account what if finddata invokes your callback with an error? Having something like:

finddata('/', function(resp){
  that.val = resp
}

Is really something what you don't want to have. With code that you have, if finddata invokes your callback with an error, val would be equal to that error, otherwise it would be equal to null, if finddata complies to node best practices to invoke callback with null if there was no errors, such as cb(null, data).

Besides that what you are trying to do? Is there a need for exposing module with val thing? Is get function meant to be called regularly from app? If so why introducing new module, just call finddata which is i guess module by itself already.

Srle
  • 10,366
  • 8
  • 34
  • 63