javascripteventssynchronizationdom-eventsweb-frontend

Javascript tabs synchronization and server events


I need some help for my application and sorry for my English.

I'm working on front-end of a website. The final app should work fine with a lot of tabs (~100 in a single browser). Each tab needs to listen for a series of events sent from server and change its content dynamically.

I implemented this feature by using Websocket. Since opening a connection is very expensive. So I assigned a master tab, which will listen to events from the server and distribute them to other tabs using BroadcastChannel. And I have following questions:


How to pick a master tab from all of them and make other tabs listen to it?

I had these ideas:

1. Using BroadcastChannel.

During initilization tab asks using BroadcastChannel: "is there a master tab?". If it receives an answer, then it will continue working. If it won't receive any response, then it makes itself a master tab.

Problem:

If master tab will freeze inside of heavy loop, then it won't be able to respond in short amount of time, resulting 2 opened connections to the server and a conflict, which needs to be resolved.

2. Using LocalStorage.

During initilization tab will request some field called "X" or smth. If field is empty, then tab will create that field and assign some value, after it will make itself a master tab. If field "X" is not empty, then tab will make itself a slave tab.

Problem:

If two tabs will initilize in the same time, there might be a conflict:

tab_Alpha -> localStorage.getItem("haveMaster") -> undefined // There is no master, so i will make myself a master tab!
tab_Beta  -> localStorage.getItem("haveMaster") -> undefined // There is no master, so i will make myself a master tab!

tab_Alpha -> localStorage.setItem("haveMaster", true) // Now it's time to open connection and listen for events
tab_Beta  -> localStorage.setItem("haveMaster", true) // Now it's time to open connection and listen for events

And as a result, I have a conflict and two opened connections.


Can someone point out a lightweight solution to me? I will appreciate that.


After a research.

Halcyon suggested to use code from gist.github.com/neilj/4146038. But i was not satisfied with this solution, because if Math.random() will return 2 same numbers for 2 different tabs, while they will initilize, then browser will call masterDidChange() two times. And browser will end up, with conflict and 2 connections.

Then Dimitry Boger suggested to read this: alpha.de/2012/03/javascript-concurrency-and-locking-the-html5-localstorage.
I liked this solution more, but i still have managed to find a way to break it.
If each tab will freeze in couple of places, then it will result, again, an execution of criticalSection().

Then i found a wikipedia.org/wiki/Peterson's_algorithm. I have not found a method to break this locking mechanism, but there is a problem.
For this algorithm to work browser have to know exact amount of tabs before execution. Because if it will initilize a new tab, then previous one's can just miss this event and start their criticalSection() before the new tab will finish it's own.

So, if you are not scared of 1024 tabs initilizing and freezing them selves at the same time, then you can use any of this solutions. But i need a bullet proof one, so i decided, to give a honor of finding a master tab to the backend server.

Thanks everyone for help.


After another research.

There is a bullet proof answer under the post. It can work without a backend server.


Solution

  • SharedWorker can be used to solve the problem.

    It will use dedicated blocking thread for all of communication between itself and other browser contexts (tabs/iframes). So it can be used to sync different things.

    MDN Article about SharedWorker