How to maintain a WebSockets connection between pages?

Unfortunately, the cleanest solution without changing your site in a SPA application is obtained using just one ServiceWorker because it does the job in the background (also with tab closed) and it solve also problems of multiple tabs. I said "unfortunately" because they are still not compatible with most of browsers.

The only solution I've found by myself consists of grouping socket channels on the server side, and create a queue in order to hold the messages lost by changing page. In this case, you have kind of virtual channels.


You could try creating your WebSocket connection in a Shared WebWorker which allows multiple pages from the same domain to share an execution context. However, it's unclear whether Shared Workers persist across a page reload or replace: Do Shared Web Workers persist across a single page reload, link navigation

Also, Shared WebWorkers have limited browser support (webkit and Opera) currently.

Update:

Since a single shared web worker can serve multiple pages, the implementation is slightly more complicated that normal web workers.

Here is a shared web worker example that uses WebSockets and can share between

First the HTML:

<!DOCTYPE html>
<html>
<body>
<script>
    var worker = new SharedWorker("shared.js");
    worker.port.addEventListener("message", function(e) {
        console.log("Got message: " + e.data);
    }, false);
    worker.port.start();
    worker.port.postMessage("start");
</script>
</body>
</html>

The Javascript that implements the shared worker in shared.js:

var ws = null
var url = "ws://" + location.hostname + ":6080"
self.addEventListener("connect", function(e) {
    var port = e.ports[0]
    port.addEventListener("message", function(e) {
        if (e.data === "start") {
            if (ws === null) {
                ws = new WebSocket(url);
                port.postMessage("started connection to " + url);
            } else {
                port.postMessage("reusing connection to " + url);
            }
        }
    }, false);
    port.start();
}, false);

I have verified that this works in Chrome 52.


The global scope you mentioned is always related to the JavaScript Context, and a Context is created for each windows (and destroyed when the document is unloaded from the memory). Therefore, your effort are useless: you can't keep a connection opened if the user change page. Of course you can have your webapp as "single page" application, where all the data are loaded using XMLHttpRequest / ajax / WebSocket. So, leaving the page means leaving / shutdown the application, and makes sense close the socket.

Another old approach could be put your pages in a frame, where the user navigate only in the frame (even if it takes the whole size of the window). In that way, you can create your WebSocket in the top most window, that is never changed (that also means the URL showed in the location bar will be always the same).

Said that, I agreed with @dystroy: your application should be always able to handle this scenario - the user could have some network problem and lost the connection for a moment, even if it doesn't leave the page.