简体   繁体   中英

Node.JS Callback Scoping Issues

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..

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
  }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM