我正在Node.js中开发浏览器游戏,我有这个脚本:
游戏.js>>
var config = require('./game_config.js');
var mysql = require('mysql');
var app = require('express')();
var http = require('http').Server(app);
var io = require('socket.io')(http);
var connexion = mysql.createConnection({
'host': config.DB_HOST,
'user' : config.DB_USER,
'password' : config.DB_PASS,
'database' : config.DB_NAME
});
var Player = require('./server/class.player.js');
io.on('connect', function(socket) {
console.log('Co');
var player
socket.on('login', function(data) {
connexion.query("SELECT * FROM player WHERE nick = '"+data.login+"' AND pass = '"+data.pass+"'", function(err, rows) {
if (err) {
throw err;
} else {
if (rows.length == 0) {
var dataRet = "LOG";
socket.emit('login', dataRet);
} else {
var p = rows[0];
var dataRet = new Player(p.id, p.nick, p.map_id, p.x, p.y, connexion).toJson();
console.log(dataRet);
}
// Without setTimeout it wouldn't work because the object didn't have the time to instantiate
setTimeout(function() {
socket.emit('login', dataRet);
},1000);
}
});
});
socket.on('disconnect', function(socket) {
console.log('Disco');
});
});
.class。播放器.js>>
var Player = function (id, name, map_id, x, y, connexion) {
this.id = id;
this.name = name;
this.map_id = map_id ;
this.x = x;
this.y = y;
this.link = connexion;
this.toJson = function () {
return {
'id' : this.id,
'name' : this.name,
'map_id' : this.map_id,
'x' : this.x,
'y' : this.y
};
}
}
module.exports = User;
所以基本上,我的代码工作正常,这要归功于游戏中的"setTimeout((".js(对于socket.emit((事件(。如果我不使用它,由于 Node.js 的异步性,对象 'dataRet' 没有时间实例化,因此套接字发出"未定义"或"null"。
所以我在想,必须有一种方法来侦听对象实例化,以便在完成后立即通过 socket.io 发出它。
警告:SQL 注入漏洞
这本身与您的问题无关,但这非常重要 - 您有一个巨大的SQL注入漏洞,任何人都可以对您的数据库执行任何操作。
而不是:
connection.query(
"SELECT * FROM player WHERE nick = '"
+ data.login + "' AND pass = '" + data.pass + "'",
function (err, rows) {
//...
}
);
要么使用:
connection.escape(data.login)
和connection.escape(data.pass)
代替data.login
和data.pass
或:
connection.query(
"SELECT * FROM player WHERE nick = ? AND pass = ?", [data.login, data.pass],
function (err, rows) {
// ...
}
);
它不仅更安全,而且实际上更容易阅读和理解。请参阅:node-mysql 手册中的转义查询值。
答案
现在,回到你的问题。您的播放器构造函数没有任何异步内容,因此您的问题一定是其他问题。奇怪的是,您的播放器.js导出User
(未定义(而不是Player
(已定义(,所以我很惊讶它甚至根本有效。或者,您可能发布了与您实际使用的代码不同的代码,这可以解释为什么您的竞争条件从代码中不明显。
但是,如果您的 Player 构造函数正在进行一些异步调用,那么我建议添加一个回调参数并从构造函数调用它:
var Player = function (id, name, map_id, x, y, connexion, callback) {
this.id = id;
this.name = name;
this.map_id = map_id ;
this.x = x;
this.y = y;
this.link = connexion;
this.toJson = function () {
return {
'id' : this.id,
'name' : this.name,
'map_id' : this.map_id,
'x' : this.x,
'y' : this.y
};
}
// some async call that you have to wait for
// symbolized with setTimeout:
setTimeout(function () {
if (callback && typeof callback === 'function') {
callback(this);
}
}, 1000);
}
然后你可以将回调传递给你的构造函数,这样:
} else {
var p = rows[0];
var dataRet = new Player(p.id, p.nick, p.map_id, p.x, p.y, connexion).toJson();
console.log(dataRet);
}
// Without setTimeout it wouldn't work because the object didn't have the time to instantiate
setTimeout(function() {
socket.emit('login', dataRet);
},1000);
可以更改为类似以下内容:
} else {
var p = rows[0];
var dataRet = new Player(p.id, p.nick, p.map_id, p.x, p.y, connexion, function () {
socket.emit('login', dataRet);
}).toJson();
console.log(dataRet);
}
但在这里,正如我所说,没有什么是异步的,而且你的dataRet
甚至在你运行 setTimeout 之前就已经设置好了,所以这并不能解决你的问题,但它正在回答你的问题。