¿Es posible escuchar la instanciación de objetos en Node.js?

Estoy trabajando en un juego de navegador en Node.Js y tengo este script:

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, px, py, 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; 

Básicamente, mi código funciona bien gracias al “setTimeout ()” en game.js (para el evento socket.emit ()). Si no lo uso, el objeto ‘dataRet’ no tiene tiempo para crear una instancia debido a la asincronía de Node.js, por lo que el socket emite “undefined” o “null”.

Así que estaba pensando, DEBE haber una manera de escuchar una instanciación de un objeto para emitirlo a través de socket.io tan pronto como se hace.

Advertencia: Vulnerabilidad de inyección de SQL

Esto no está relacionado con su pregunta en sí, pero es muy importante: tiene una gran vulnerabilidad de inyección de SQL y cualquiera puede hacer cualquier cosa en su base de datos.

En lugar de:

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

o bien usar:

connection.escape(data.login) y connection.escape(data.pass) en lugar de data.login y data.pass

o:

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

No solo es más seguro sino que también es mucho más fácil de leer y entender. Consulte: Escape de los valores de consulta en el manual de node-mysql .

La respuesta

Ahora, volvamos a tu pregunta. No hay nada asíncrono en su constructor Player, por lo que su problema debe ser otra cosa. Lo que es extraño aquí es que su Player.js exporte un User (que no está definido) y no un Player (que está definido), así que me sorprende que incluso funcione. O tal vez haya publicado un código diferente al que está usando en realidad, lo que explicaría por qué tiene una condición de carrera que no es evidente en el código.

Pero si su constructor de Player estaba haciendo algunas llamadas asíncronas, sugeriría agregar un argumento de callback y llamarlo desde el constructor:

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

y luego puede pasar una callback a su constructor, por lo que esto:

  } else { var p = rows[0]; var dataRet = new Player(p.id, p.nick, p.map_id, px, py, 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); 

podría cambiar a algo como:

  } else { var p = rows[0]; var dataRet = new Player(p.id, p.nick, p.map_id, px, py, connexion, function () { socket.emit('login', dataRet); }).toJson(); console.log(dataRet); } 

pero aquí, como dije, nada es asíncrono y también su dataRet ya está configurado incluso antes de ejecutar setTimeout, por lo que esto no resuelve su problema, sino que responde a su pregunta.