在模块中两次调用相同的函数失败
我正在创建一个node.js模块来与机器人交互,我必须根据另一个REST调用的结果获得一个REST资源(两者都是GET)。
当我这样做时,我首先调用模块中的一个函数来构造REST资源的url,然后我在“node-rest-client”模块中使用它。
问题是我需要将这个模块用于多个机器人,这些机器人具有单独的ip地址和一些不同于机器人到机器人的其他参数(如果你愿意,我需要将它作为一个类使用)。
我的模块被称为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
在函数内部调用时的上下文。
在为bind(this)
声明回调函数时,你应该使用rest.get
:
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));
}