socket.io "connect" event on refresh/reload wont fire

signal_intrusion picture signal_intrusion · Dec 9, 2013 · Viewed 8.1k times · Source

Having an issue with socket.io today. When I refresh a page .on("connect", {}) never fires. When I load a page from the url all events fire as they should. As you can see below I set the gameStatus to broken. After a series of client/server communications the game status should update to "ready" and a new player should be created on the server. When I reload the page (cmd+r), none of the client side events fire.

The server side recognizes the new connection "sees" the new socket.id and emits the "send room" event, but the event is not received on the client side.

I tried to force new connection, but I don't know whether or not I am using that correctly.

Last week this worked as I expected, then today without even updating the code, it can't get those events to fire on page refreshes. Everything works as it should if I load the page from the full url (http://localhost:3000 in this case)

index.html:

var io = io.connect('/', {'force new connection': true});

client.js

var gameStatus = 'broken';
var localPlayer;

window.onload = function() {

  console.log(gameStatus);  // "broken"

  io.on("connect", onSocketConnected);
  io.on("disconnect", onSocketDisconnect);
  io.on("new player", onNewPlayer);
  io.on("send room", function(data){
        console.log("send room fired"); // doesn't fire on refresh
        addPlayer(data);
  });
}

function onSocketConnected() {
    console.log("Connected to socket server "); // doesn't connect on refresh
    // assign socket.sessionid as the player name
    localPlayer.id = io.socket.sessionid;
    io.emit("new player", {id: localPlayer.id});
    console.log(localPlayer.id); // "undefined" on refresh
}

function onSocketDisconnect() {
    console.log("Disconnected from socket server");
}

function addPlayer(data) {
    console.log("addPlayer fired"); // doesn't fire on refresh
    gameStatus = data.roomStatus;
}

server.js:

io.sockets.on('connection', function (socket) {

    socket.on("disconnect", onClientDisconnect);
    socket.on("new player", onNewPlayer);

});

io.sockets.on("connection", onSocketConnection);

function onSocketConnection(socket) {

    console.log("New player has connected: " + socket.id);
    var lastRoom = rooms.length-1;  // simplified for stackoverflow

    // send the playerType and roomNum to the client
    io.sockets.in(lastRoom).emit('send room', { roomStatus: "ready" });

}

function onNewPlayer(client) {

   console.log("new player created!"); // only on first page load

    var newPlayer = new Player(client.id); 
    players.push(newPlayer); // add player to player array
}

function onClientDisconnect(socket) {

    util.log("Player has disconnected: " + this.id);
    var disRooms = io.sockets.manager.roomClients[this.id];
    for (var room in disRooms) {
        if (room.length > 0) { // if not the global room ''
            room = room.replace(/\//g, '')
            console.log('user exits: '+room);
            this.broadcast.to(room).emit('player left');
        }
    }
}

Answer

signal_intrusion picture signal_intrusion · Dec 10, 2013

After much gnashing of teeth, I discovered that the exposed "connect" method of socket.io fires before window.onload when a page is refreshed. So my event handlers weren't set up by the time the server emits "connect." If the client misses that first "connect" everything else came apart. I fixed the problem by moving the event handlers out of window.onload.

You might find other solutions, but this was mine:

var gameStatus = 'broken';
setEventHandlers();
console.log(gameStatus);  // "broken"

window.onload = function() {
    // other stuff
}

function setEventHandlers(){
  io.on("connect", onSocketConnected);
  io.on("disconnect", onSocketDisconnect);
  io.on("new player", onNewPlayer);
  io.on("send room", function(data){
        console.log("send room fired"); // fires as expected
        addPlayer(data);
  });
}

function onSocketConnected() {
    console.log("Connected to socket server "); // connects before window loads
    // assign socket.sessionid as the player name
    localPlayer.id = io.socket.sessionid;
    io.emit("new player", {id: localPlayer.id});
}

function addPlayer(data) {
    gameStatus = data.roomStatus;
    console.log(gameStatus);  // "ready"
}