When I start a new instance of GameServer, it sets up the socket and listeners as follows.
var GameServer = function() {
this.player = new Player();
var that = this;
// Setup sockets and listeners
var socket = io.listen(8000);
socket.sockets.on('connection', function(client) {
client.on('message', that.onSocketMessage);
client.on('disconnect', that.onSocketDisconnect);
});
}
I then have two prototypes GameServer.prototype.onSocketMessage & onSocketDisconnect.
I have two problems with the current code:
Using that = this and the closure? function. Looks ugly.
When onSocketMessage is called, the idea is it works out what the message is then calls another function within GameServer. Only this isn't possible as now this belongs to the socket.io system. See below:
...
function onSocketMessage() {
this.player.move();
}
this.player is no longer available as this. is no longer part of GameServer.
Should my socket setup and message passing be handled outside of GameServer function and prototypes?
Or how else could I resolve this?
Cheers
EDIT
Ok so I have tried this and it works but looks pretty ugly I think:
var socket = io.listen(8000);
socket.sockets.on('connection', function(client) {
client.on('message', function (data) {
that.onSocketMessage(this, that, data);
});
client.on('disconnect', function() {
that.onSocketDisconnect(this, that);
});
});
Can it be improved upon?
Two things that may help. Thing the first:
You can modify a function's vision of this using the bind method.
socket.sockets.on('connection', function(client) {
client.on('message', this.onSocketMessage);
client.on('disconnect', this.onSocketDisconnect);
}.bind(this));
Notice the call to bind(this) at the end of the function; this instructs JavaScript to create a closure for you, making whatever this is outside the function, this inside the function. (If you wanted to make this inside the function, say, MySomething, you could just as easily call bind(MySomething), though bind(this) is the most common use).
Thing the second:
You can store data in a Socket.IO socket. So, for example, if one socket is always associated with a player, you can do
socket.set('player', player, function() {
// callback is called when variable is successfully stored
console.log('player has been stored');
});
// and later
socket.get('player', function(err, player) {
// callback is called either with an error set or the value you requested
player.move();
});
The get and set methods take callbacks because the Socket.IO data store can be set to something other than an in-memory store; for example, Redis.
Related
I'm trying to create an object with "callback" type functions that work like the functions on a websocket. I cannot for the life of me figure out the right language for what I should be googling to figure this out.
If I create a websocket, it might look like this
var ws = new WebSocket("ws://myUrl");
ws.onopen = function() {
// Do things with open socket
}
ws.onmessage = function(e) {
// Do things with e
}
ws.onclose = function() {
// Do things with closed socket
}
Simple, easy to use, very straightforward.
I want to create my own object/class. We'll call it FancyWebSocket. What would the backend of FancyWebSocket need to look like in order to have onopen and onmessage work correctly? I need it to work exactly like a WebSocket works, because I will be passing either FancyWebSocket or WebSocket to another object, and that other object needs to interact with both of them the same.
Sorry this feels like it should be simple and I'm just going crazy trying to find it.
Here's what I'm testing right now that I think works? It looks like I just define the function signature as an empty function inside the class, then when I create the object I can declare that same signature as another function and it overwrites the original one internal to the class and works.
I think this works, posting it as an answer and hoping either I'm right or someone will come along and explain why I'm still wrong.
class FancySocket {
constructor(port) {
this.port = port;
}
connect() {
console.log(`Connecting to ${this.port}`);
this.onopen();
}
onopen = function () {};
}
var fancySocket = new FancySocket(42);
fancySocket.onopen = function () {
console.log('Socket Opened');
};
fancySocket.connect();
Outputs
Connecting to 42
Socket Opened
I know the issue I am facing, but not sure how to solve it. Basically I have a Room class that stores Clients. When they join the room, handlers are attached to them. When they leave, handlers are removed. However, because I am using bind (and don't mind changing it if possible) I can't figure out how to call off and pass the correct function reference.
class Room {
atttachClientHandlers(client){
client.on('data', this.handleData.bind(this, client);
}
detachClientHandlers(client){
client.off('data', this.handleData);
}
handleData(client, data){
// do something
}
}
let client = new Client();
let room = new Room();
room.attachClientHanlders(client); // ok
room.detachClientHandlers(client); // never detaches it
I don't see anywhere I can store the handler for this client, or how I can give a name to the function callback.
The main thing to do is to store the function reference when it's created, like so:
attachClientHandlers(client){
this.boundHandleData = this.handleData.bind(this, client);
client.on('data', this.boundHandleData);
}
Your detach method can then pass this reference to off if the reference exists:
detachClientHandlers(client) {
if (this.boundHandleData) {
client.off('data', this.boundHandleData);
}
}
I'm trying to use the NodeJS module "pcsc-lite" to communicate with a card reader. If you want to take a look at the module : https://github.com/santigimeno/node-pcsclite.
I'm looking for a way to send a sequence of data to my reader using my own method. Because, the module is event-based. So I have to declare two listeners (one in the other) to be able to call the send method.
For example :
module.on("reader", function(reader){
//...
reader.on("status", function(status){
//...
reader.connect({ share_mode : this.SCARD_SHARE_SHARED },function(err, protocol) {
//This is the method I want to be able to call "when I need it"
reader.transmit(...);
});
});
});
I would like to call the transmit method like this for example :
function send(...){
reader.transmit(...);
}
I think there is a way to do it, but I seem to be a little bit hooked to my C/Java programming habits.
Thanks in advance.
If your reader will be a singleton, you can declare it outside the callback, and then assign the variable when you're ready. Without knowing more, here's a simple example:
let reader; // we prepare a variable that's outside of scope of it all.
// your `send` function
function send(params) {
let stuff = doStuffWithParams(params);
reader.transmit(stuff, callback);
}
// we take out init stuff too
function initialize() {
// we know reader variable is already initialized.
reader.on('status', function() {
reader.connect({
share_mode : this.SCARD_SHARE_SHARED
},function(err, protocol) {
// send.
send();
// or even better, emit some event or call some callback from here, to let somebody outside this module know you're ready, then they can call your `send` method.
});
});
}
// now your module init section
let pcsc = require('pcsclite')();
pcsc.on('reader', function(r) {
// assign it to our global reader
reader = r;
initialize();
});
Note: don't call your variables module, it's refering to the file being currently executed and you can get unexpected behavior.
I am taking jQuery.Atmosphere.js as an example, in this it has public function such as onMessage, onError etc. And when implementing this api i have done the following
var socket = $.atmosphere;
var request = new $.atmosphere.AtmosphereRequest();
request.onMessage = function(response) {
// do what i want to do
}
Here the onMessage will be trigger whenever the server pushes data to browser. I don't understand how request.onMessage(response) get notified which is outside the atmosphere api? I have looked in to the jQuery.Atmosphere.js and couldn't connect the dots how this works. I am not talking about websocket or server push or anything about atmosphere framework. I just want understand how javascript function callbacks work. Can anyone point me an example how function callbacks work or send me a link so i can dig in?
Your syntax is incorrect, it should be:
request.onMessage = function(response) {
// do what I want to do
};
As you can see, the onMessage property must be set to a function. When the Message event occurs on this object, the function will be called. The jQuery.Atmosphere.js code contains:
f.onMessage(response);
where f is its internal variable representing the AtmosphereRequest object. This function is called from invokeFunction():
function _invokeFunction(response) {
_f(response, _request);
// Global
_f(response, jQuery.atmosphere);
}
_request is a local variable in the AtmosphereRequest constructor, which contains all the state of this request object. This is part of Javascript object oriented programming; all uses of this AtmosphereRequest object have access to these internal state variables.
For the full story, check out my other question.
Basically, I had asked if it were more efficient to use named functions in the socket handlers for the following code:
var app = require('express').createServer()
var io = require('socket.io').listen(app);
app.listen(8080);
// Some unrelated stuff
io.sockets.on('connection', function (socket) {
socket.on('action1', function (data) {
// logic for action1
});
socket.on('action2', function (data) {
// logic for action2
});
socket.on('disconnect', function(){
// logic for disconnect
});
});
The overall answer was yes (see the above link for more details), but the following comment was posted by ThiefMaster:
I'm not familiar with V8 internals but it might be smart enough to compile the function once and re-use it everytime, just with a different scope attached.
So now that's my question. Is V8 smart enough to compile anonymous functions once and reuse them with different scopes in situations where anonymous functions ordinarily lead to several function instances being created? For example, above I would expect the handler for the connection event to be created once but the handlers for action1, action2, and disconnect to be created for each connection. In the other question this was solved with named functions but I am more interested if this is necessary in V8 or if it will do some optimizations.
Yes. I asked a very similar question (related in my case to creating functions from within a constructor function) on the V8 mailing list. I got the reply that the function's code is "...normally reused...", even though there's a separate function object each time (as required by the spec).
Note, though, that your question has nothing to do with whether the function is named or anonymous. The function in your example could have a name:
io.sockets.on('connection', function handleConnection(socket) {
socket.on('action1', function (data) {
// logic for action1
});
socket.on('action2', function (data) {
// logic for action2
});
socket.on('disconnect', function(){
// logic for disconnect
});
});
That uses a named function expression, which is perfectly valid and handled correctly by V8. (Sadly, it's not handled correctly by IE8 and earlier, which create two completely different functions at totally different times. But as you're using V8, you don't have to worry about that.)