In a browser, each tab is an independent instance. When more than one tabs hitting the same web site ([protocol]://[host]:[port]), they don't share states stored in the memory. To keep the states in sync across multiple tabs, we can take advantage of one of the following technologies:
In the following sections, we will use these technologies to implement a set of use cases:
Tabs visiting the same origin share the same localStorage object. A storage event of the Window interface fires when localStorage has been modified in the context of another document. We can rely on the storage event to "broadcast" changes to other tabs.
For instance, we designed a simple flow in this demo:
BroadcastChannel allows communication between tabs and workers on the same origin. Tabs can set up a STATE_UPDATED channel sync communicate state changes.
Compared to the localStorage approach, broadcast channel is more straightforward and performant. The API is specifically designed for sending a broadcast message. The message can be any type of object. Both sender and receiver tabs can work with the object without serialization.
The demo works in the following ways:
All tabs of the same origin shares the same instance of a service worker. In a environment where broadcast channel is not available, service worker can be used to post messages to other tabs.
To post a message from client to service worker:
navigator.serviceWorker.controller.postMessage(message);
To post a message from service worker to clients:
const clients = await self.clients.matchAll({
type: 'window',
});
if (clients) {
for (const client of clients) {
client.postMessage(message);
}
}
It's worth noting that service worker may terminate after 30 seconds of inactivity. Posting a message would wake up the service worker. This process would add extra latency.
The demo works in the following ways: