0
votes

I'm using JavaScript classes to write a small tool for work. I don't like callbacks nesting and nesting, so I like to break them out into separate functions. I'm trying to run requests, which take a callback, from within a for...of loop. The problem is, when I break the callback out into a separate function, it looses the scope of the for...in loop and it doesn't know what "service.url" is.

Here is my code:

const DATA = require("../resources/data.json");
const Request = require("request");

class Net {
    constructor(){}

    _handleResponses(e, r, b) {
        console.log("--------------------------------------------------------------");

        if(r.statusCode == 404) {
            console.log("\x1b[31m"+`[RESPONSE](Status  ${r.statusCode})`, "\x1b[0m");
            console.log("\x1b[31m"+`Server: ${service.server}`, "\x1b[0m");
            console.log("\x1b[31m"+`Service: ${service.service}`, "\x1b[0m");
            console.log("\x1b[31m"+`Body: ${b}`, "\x1b[0m");
        } else {
            console.log(`[RESPONSE](Status  ${r.statusCode})`);
            console.log(`Server: ${service.server}`);
            console.log(`Service: ${service.service}`);
            console.log(`Body: ${b}`);
        }
    }

    pollServices() {
        for(let service of DATA) {
            Request(service.url, this._handleResponses);
        }
    }
}

module.exports = Net;

Here is the error I get when the "pollServices" function/method runs:

C:\Users\payton.juneau\Desktop\Me\Projects\Node\com.etouchmenu.tools.crystalBall\utilities\net.js:17 console.log(Server: ${service.server}); ^

ReferenceError: service is not defined at Request._handleResponses [as _callback] (C:\Users\payton.juneau\Desktop\Me\Projects\Node\com.etouchmenu.tools.crystalBall\utilities\net.js:17:36) at Request.self.callback (C:\Users\payton.juneau\Desktop\Me\Projects\Node\com.etouchmenu.tools.crystalBall\node_modules\request\request.js:186:22) at Request.emit (events.js:159:13) at Request. (C:\Users\payton.juneau\Desktop\Me\Projects\Node\com.etouchmenu.tools.crystalBall\node_modules\request\request.js:1163:10) at Request.emit (events.js:159:13) at IncomingMessage. (C:\Users\payton.juneau\Desktop\Me\Projects\Node\com.etouchmenu.tools.crystalBall\node_modules\request\request.js:1085:12) at Object.onceWrapper (events.js:254:19) at IncomingMessage.emit (events.js:164:20) at endReadableNT (_stream_readable.js:1062:12) at process._tickCallback (internal/process/next_tick.js:152:19)

Any help would be much appreciated, kind of new to all of this type of stuff..

1
Please post the code and not the screenshots - nem035
You just forgot to pass service as an argument ... - pirs
Code added as text - user4158347
Why did you remove the content from your question leaving an absolutely worthless reference behind? This is NOT how you use stack overflow. - jfriend00

1 Answers

1
votes

When you define 2 methods on a class, they each create their own independent scope:

class Example {
  method1() {
    // scope of method 1 only visible to method 1
    let hiddenInM1 = 'example'; // <-- only available here
  }
  method2() {
    // scope of method 2 only visible to method 2
    // I don't know what m1 is
  }
}

There are 3 ways for these methods to share values with each other.

1. Using a variable available in an outer scope in which both of these methods belong to:

let sharedGlobal = 'example';
class Example {
  method1() {
    // I can see sharedGlobal
  }
  method2() {
    // I also can see sharedGlobal
  }
}

This is usually ill-advised because global state is prone to bugs.

2. Through the context of the class those methods belong to (via this)

class Example {
  constructor() {
    this.sharedClassVar = 'example'
  }
  method1() {
    // I can see this.sharedClassVar
  }
  method2() {
    // I also can see this.sharedClassVar
  }
}

3. By passing arguments to each other.

class Example {
  method1(fromMethod2) {
    // I can receive stuff from method2
  }
  method2() {
    this.method1('example')
  }
}

If you look at your code, none of these patterns are present and thus _handleResponses doesn't have access to the service defined in pollServices.

The easiest change you can make is to pass the service yourself:

_handleResponses(service, e, r, b) {
  //             ^^^^^^^ receive the service here
}

pollServices() {
  for (let service of DATA) {
    Request(service.url, (...args) => this._handleResponses(service, ...args))
    //                                                      ^^^^^^^ pass the service with the args
  }
}