To share one WebSocket
connection between different html pages, you need to use SharedWorker
.
I have researched a similar topic and made a simple example by chance so I'd like to make brief explanation about it and show simple example source code.
Solutions to what you want to achieve
From your question
What I want to achieve is, have events done on
different HTML pages trigger changes to particular another one.
WebSocket
instance on all pages
SharedWorker
It can be achieved by creating WebSocket
connection on all pages(solution 1).
When you want to reduce the number of WebSocket
connection per each client(to reduce the server load), SharedWorker would be a better choice(solution 2).
I think you have already understood solution 1 and are looking for a better solution so you ask:
How to share a WebSocket connection between different html pages?
So I'd like to write mainly about SharedWorker
here.
[NOTE]
You can't share WebSocket
connection by using sessionStorage
and localStorage
because they don't store javascript object itself but handle string key/value pairs(
Storing Objects in HTML5 localStorage).
About Shared Worker
From SharedWorker -
MDN,
a specific kind of worker that can be accessed from several browsing
contexts, such as several windows, iframes or even workers.
Worker(Web Worker) is javascript running in the background.
You can use WebSocket
in worker.
When you create the connection in SharedWorker
, you can use the same(shared) connection in multiple html pages via the worker.
Shared Worker Simple Example
We have 2 different html pages:
http://localhost:8080/pageA.html
http://localhost:8080/pageB.html
They have a button named message
.
When the button is clicked:
- They send a message to
SharedWorker
and the worker sends the message to the server using shared WebSocket
connection.
- The server responds to the client's message and send a message to the worker.
- The 2 html pages recieve the server's message from the worker.
[server side - WebSocketHandler using Spring]
/**
* End point '/hellows'
*/
public class MyWebsocketHnadler extends TextWebSocketHandler {
@Override
protected void handleTextMessage(WebSocketSession session, TextMessage message) throws Exception {
System.out.println("Message from client : " + message.getPayload());
session.sendMessage(new TextMessage("Server responds to '" + message.getPayload() + "'"));
}
@Override
public void afterConnectionEstablished(WebSocketSession session) throws Exception {
System.out.println("Connection is opened.");
session.sendMessage(new TextMessage("Open"));
}
}
[client side - pageA.html & pageB.html]
<!-- For simplicity I omit DOCTYPE, html tag, head tag and body tag here -->
<button type="button" id="msg-btn"/>message</button>
<script src="main.js"></script>
[client side - main.js]
const worker = new SharedWorker("worker.js");
worker.port.start();
// post message in order to make worker to push this page's port to port array.
worker.port.postMessage({ id: location.href });
worker.port.addEventListener("message", e => console.log(e.data.msg));
document.querySelector("#msg-btn").addEventListener("click", () => {
worker.port.postMessage({ msg: "I am " + location.href });
});
[client side - worker.js]
const ports = {};
const ws = new WebSocket("ws://localhost:8080/hellows");
ws.addEventListener("message", e => {
Object.values(ports).forEach(port => {
port.postMessage({ msg: "From sever: " + e.data });
});
});
addEventListener("connect", e => {
const port = e.ports[0];
port.start();
port.addEventListener("message", e => {
// if you open same html page at multiple windows,
// only newest window can send and recieve a message.
if (e.data.id) ports[e.data.id] = port;
if (e.data.msg) ws.send(e.data.msg);
});
});
When we access pageA
and pageB
and then click message
buttons one after the other, we get the result like this:
[server side - console]
Connection is opened.
Message from client : I am http://localhost:8080/pageA.html
Message from client : I am http://localhost:8080/pageB.html
Message from client : I am http://localhost:8080/pageA.html
[client side - pageA.html's console]
From sever: Open
From sever: Server responds to 'I am http://localhost:8080/pageA.html'
From sever: Server responds to 'I am http://localhost:8080/pageB.html'
From sever: Server responds to 'I am http://localhost:8080/pageA.html'
[client side - pageB.html's console]
From sever: Server responds to 'I am http://localhost:8080/pageA.html'
From sever: Server responds to 'I am http://localhost:8080/pageB.html'
From sever: Server responds to 'I am http://localhost:8080/pageA.html'
Consideration
- What browsers do you have to support?
Some browsers don't support Shared Worker(Can I use ...).
See Also:
Web Workers API - MDN
SharedWorker - MDN
Scaling WebSocket Connections using Shared Workers - Ayush Gupta