简体   繁体   中英

Send SocketIO message on unload or upon confirmation onbeforeunload

I have a server application that performs firmware update on remote devices via radio.

Sometimes the update may continue like forever(if there is disturbance in the radio network). In that case the user may wish to interrupt the update by refreshing or leaving the page. In this case I have to:

  1. Alert the user that he is about to interrupt the update(which is not recommended), and if the user is sure about his decision(and confirm):

  2. Send a socketIO event to the server to inform that the update should be canceled.

I searched trough the internet and came across to different solutions. The best of them are assigning handlers to the global object events onbeforeunload and onunload .

  • Using onbeforeunload I don't have choice. Can't send the SocketIO message only if the user confirm, and do nothing if the user decide to wait the update to finish. I can send the SocketIO message to the server, but what if the user decide to wait? The harm is already done.

  • Using onunload - it seems that doesn't work for me. I see that the socket event is being send by the browser, but before handled by the server the connection is closed.

Is there any way keep the SocketIO connection or delay the browser refresh so the server can handle the event.

I think that this is problem in the server because it runs on CPU with very limited resources, even CPU speed. It is ARM A7 architecture.

There is a way:

Server: Create a user id with:

var custom_id = 0;
io.engine.generateId = (req) => {
    let id = custom_id++;
    return id++; // very basic but unique id
  }

Server: Create a listener to an attempt to close event and store the user id attempt:

var userAttempt = 0;

socket.on('attempt to close', function(data){
  userAttempt = socket.id;
  console.log(data)
})

Server: Modify disconnect event to check which id user is disconnected:

socket.on('disconnect', function(){
    if(userAttempt === socket.id){
      console.log("user attempt and close");
     //the update should be canceled !!!!
    }
    console.log('user disconnected');
  });

Client: Create the event emitter attempt to close inside onbeforeunload , this event is always going to be fired if user attempt to close or reload the page.

window.onbeforeunload = function (e) {
      e.returnValue = " ";
      var socket = io();
      socket.emit('attempt to close', "user attempt to close");
    };

If user try to close the tab, we fire the event attempt to close , we check if user close or not the tab checking the disconnect event. If user disconnected is the same as user attempted to close, the update should be cancelled.

What I did is place the socket event in window.addEventListener('unload', function (e) {});

    window.addEventListener('beforeunload', function (e) {
        e.preventDefault();
        e.returnValue = ' ';
    });


    window.addEventListener('unload', function (e) {
        socket.emit('some event', {data to be sent});
    });

it worked fine to accomplish the task

Although this doesn't fully answer the question, here are some observations I've made using Chrome Version 95.0.4638.54 (Official Build) (64-bit) and socket.io.

  1. The window.beforeunload or window.unload events cause the socket to disconnect before you can send a message via socket.io that the window/tab is closing.

  2. It's probably better to manage this on the server where you can detect the disconnection:( https://socket.io/docs/v4/server-api/ )

    socket.on("disconnect", (reason) => {

     // reason = disconnect, server shutting down, ping timeout, //transport close, transport error console.log('disconnect:'+reason+ ' '+socket.id); //then do your stuff

    });

    If you're managing the connections between user ids and socket ids on the server it's posssible to track who is doing what etc. I suspect that the answers given may have worked 3 yrs ago but Chrome has changed a lot and I always got a socket disconnect before I could use socket.emit.

    Hopefully this will help.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM