一尘不染

是否可以在Node.js中监听对象实例化?

node.js

我正在Node.Js中开发一个浏览器游戏,并且我有这个脚本:

game.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.Player.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;

所以基本上,由于game.js中的“
setTimeout()”(对于socket.emit()事件),我的代码可以正常工作。如果我不使用它,由于Node.js的异步性,对象’dataRet’没有时间实例化,因此套接字发出“
undefined”或“ null”。

所以我在想,必须有一种侦听对象实例化的方法,以便在完成后立即通过socket.io发出它。


阅读 274

收藏
2020-07-07

共1个答案

一尘不染

警告: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.logindata.pass

要么:

connection.query(
  "SELECT * FROM player WHERE nick = ? AND pass = ?", [data.login, data.pass],
  function (err, rows) {
    // ...
  }
);

它不仅更安全,而且实际上更容易阅读和理解。请参阅:转义查询的值节点MySQL手册

答案

现在,回到您的问题。关于Player构造函数,没有什么异步的,因此您的问题必须是其他问题。这里让我们感到奇怪的是,Player.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之前就已经设置好了,所以这不能解决您的问题,但可以回答您的问题。

2020-07-07