在一个模块中调用同一个函数两次失败

Calling the same function twice in a module fails

我正在制作一个 node.js 模块来与机器人交互,我必须根据另一个 REST 调用的结果获取 REST 资源(两者都是 GET)。

当我这样做时,我首先调用模块内的函数为 REST 资源构造 url,然后我在 "node-rest-client" 模块中使用它。

问题是我需要将此模块用于多个机器人,这些机器人具有单独的 IP 地址和一些其他参数,这些参数因机器人而异(我需要将其用作 class如果你愿意的话)。

我的模块叫做mir100.js,如下

var Client = require('node-rest-client').Client;
var rest = new Client(); 

/* Make the mir function act as a constructor
* use: var robot = new mir("192.168.42.111");
* or: var robot = new mir();//default ip = 192.168.12.20
*/
module.exports = mir;
function mir(ip) {
    this.g_robotPositions = [];
    this.HOST = "192.168.12.20";
    this.PORT = "8080";
    this.VERSION = "v1.0.0";
    if(arguments.length === 1){ 
        console.log("IP address is defined as argument: " + ip);
        this.HOST = ip; 
    }
}

/** Construct url
* Private function/method
* @param {string} path is the path of the url resource
* @param {boolean} predefined if true, this is indicates the path is taken from the MiR REST (includes /v1.0.0/...) default=false
* @return {string} url to the desired resource
*/
mir.prototype.ConstructURL = function(path, predefined){
    if(predefined == "undefined") predefined = false;
    if(predefined == true){
        return "http://" + this.HOST + ":" + this.PORT + path;
    }
    var url = "http://" + this.HOST + ":" + this.PORT + "/" + this.VERSION
    if(path[0] == '/') url += path;
    else url += "/" + path;
    return url;
}

/** Get all details about positions belonging to a specific map (guid) 
* @param map The map guid to get positions from
* @param callback A callback function, that returns any errors that might have occurred. The callback function takes the standard javascript argument format of (error, data)
*/
mir.prototype.GetPositionsFromMap = function(map,callback){
    g_robotPositions = [];
    var url = this.ConstructURL("maps/" + map + "/positions");

    var req = rest.get(url,function(data,response){
        if(response.statusCode >= 200 && response.statusCode < 300){

            var posCnt = data.length;
            for(var ii in data){
                console.log("data["+ii+"].url: " + data[ii].url);
                // This call to ConstructURL(...) fails and says "TypeError: this.ConstructURL is not a function"
                var tmpUrl = this.ConstructURL(data[ii].url);

                var req2 = rest.get(tmpUrl,function(data,response2){
                    if(response2.statusCode >= 200 && response2.statusCode < 300){
                        g_robotPositions.push(data);
                        if(g_robotPositions.length == posCnt){
                            callback(null,g_robotPositions);
                        }
                    }
                    else{
                        var error2 = {
                            "error":response2.statusCode,
                            "url":tmpUrl,
                            "robot":this.HOST,
                            "source":"mir100.js - GetPositionsFromMap()"
                        }
                        console.log(JSON.stringify(error2),error2.source,{"robot":this.HOST});
                        callback(error, null);
                    }
                });

                req2.on("error",function(err2){
                    console.log("Error GetPositionsFromMap 2: " + err2);
                });
            }
        }
        else{
            error = {
                "error":response.statusCode,
                "url":url,
                "robot":this.HOST,
                "source":"mir100.js - GetPositionsFromMap()"
            }
            console.log(JSON.stringify(error),error.source,{"robot":this.HOST});
            callback(error, null);
        }
    });

    req.on("error",function(err){
        console.log(err,"mir100.js - GetPositionsFromMap()",{"robot":this.HOST})
        callback(err, null);
    });
}

/** Get a list of all the maps on the robot 
* @param callback A callback function, that returns any errors that might have occurred. The callback function takes the standard javascript argument format of (error, data)
*/
mir.prototype.GetMaps = function(callback){
    var url = this.ConstructURL("maps");

    var req = rest.get(url,function(data,response){
        if(response.statusCode >= 200 && response.statusCode < 300){
            callback(null, data);
        }
        else{
            error = {
                "statusCode":response.statusCode,
                "url":url,
                "robot":this.HOST,
                "source":"mir100.js - GetMaps()"
            }
            console.log(JSON.stringify(error),error.source,{"robot":this.HOST});
            callback(JSON.stringify(error), null);
        }
    });

    req.on("error",function(err){
        console.log(err,"mir100.js - GetMaps()",{"robot":this.HOST})
        callback(err, null);
    });
}

在我的主要 node.js 我有以下内容:

var mir = require('./mir100.js');

var robot = new mir();

robot.GetMaps( function(err,data){
    if(!err){
        robot.GetPositionsFromMap(data[1].guid,function(err,posData){
            if(!err){
                console.log("getPositionsFromMap: " + JSON.stringify(data));
            }
            else{
                console.log("Error getPositionsFromMap: " + err); 
            }
        });

    }
    else{
        console.log("Error GetMaps: " + err); 
    }
});

当我 运行 代码时,我在控制台中收到以下错误

TypeError: this.ConstructURL is not a function
    at C:\Projects\Active\AL10-2.0\al10-server\js\mir100.js:498:23
    at C:\Projects\Active\AL10-2.0\al10-server\node_modules\node-rest-client\lib\node-rest-client.js:539:13
    at Object.parse (C:\Projects\Active\AL10-2.0\al10-server\node_modules\node-rest-client\lib\nrc-parser-manager.js:142:13)
    at ConnectManager.handleResponse (C:\Projects\Active\AL10-2.0\al10-server\node_modules\node-rest-client\lib\node-rest-client.js:538:32)
    at ConnectManager.handleEnd (C:\Projects\Active\AL10-2.0\al10-server\node_modules\node-rest-client\lib\node-rest-client.js:531:18)
    at IncomingMessage.<anonymous    (C:\Projects\Active\AL10-2.0\al10-server\node_modules\node-rest-client\lib\node-rest-client.js:678:34)
    at emitNone (events.js:91:20)
    at IncomingMessage.emit (events.js:185:7)
    at endReadableNT (_stream_readable.js:974:12)
    at _combinedTickCallback (internal/process/next_tick.js:74:11)

为什么我不能使用这个功能两次? 我担心它与调用 ConstructURL() 周围的 for 循环有关,但我不明白为什么这会成为问题...

问题是关于 this 在函数内部调用时的上下文。

在为 rest.get 声明回调函数时应使用 bind(this):

var req = rest.get(url,(function(data,response){...}).bind(this));

而且,req.on("error", ...)也是如此。

这是 GetPositionsFromMap 的完整代码:

/** Get all details about positions belonging to a specific map (guid) 
* @param map The map guid to get positions from
* @param callback A callback function, that returns any errors that might have occurred. The callback function takes the standard javascript argument format of (error, data)
*/
mir.prototype.GetPositionsFromMap = function(map,callback){
    g_robotPositions = [];
    var url = this.ConstructURL("maps/" + map + "/positions");

    var req = rest.get(url,(function(data,response){
        if(response.statusCode >= 200 && response.statusCode < 300){

            var posCnt = data.length;
            for(var ii in data){
                console.log("data["+ii+"].url: " + data[ii].url);
                // This call to ConstructURL(...) fails and says "TypeError: this.ConstructURL is not a function"
                var tmpUrl = this.ConstructURL(data[ii].url);

                var req2 = rest.get(tmpUrl,function(data,response2){
                    if(response2.statusCode >= 200 && response2.statusCode < 300){
                        g_robotPositions.push(data);
                        if(g_robotPositions.length == posCnt){
                            callback(null,g_robotPositions);
                        }
                    }
                    else{
                        var error2 = {
                            "error":response2.statusCode,
                            "url":tmpUrl,
                            "robot":this.HOST,
                            "source":"mir100.js - GetPositionsFromMap()"
                        }
                        console.log(JSON.stringify(error2),error2.source,{"robot":this.HOST});
                        callback(error, null);
                    }
                });

                req2.on("error",function(err2){
                    console.log("Error GetPositionsFromMap 2: " + err2);
                });
            }
        }
        else{
            error = {
                "error":response.statusCode,
                "url":url,
                "robot":this.HOST,
                "source":"mir100.js - GetPositionsFromMap()"
            }
            console.log(JSON.stringify(error),error.source,{"robot":this.HOST});
            callback(error, null);
        }
    }).bind(this));

    req.on("error",(function(err){
        console.log(err,"mir100.js - GetPositionsFromMap()",{"robot":this.HOST})
        callback(err, null);
    }).bind(this));
}