我的申请需要一些帮助,对我的英语感到抱歉。
我正在开发一个网站的前端。最终的应用程序应该可以在很多选项卡上正常工作(单个浏览器中~100 个)。每个选项卡都需要侦听从服务器发送的一系列事件并动态更改其内容。
我使用Websocket实现了这个功能。由于打开连接非常昂贵。因此,我分配了一个主选项卡,它将侦听来自服务器的事件并使用 BroadcastChannel 将它们分发到其他选项卡。我还有以下问题:
如何从所有选项卡中选择一个主选项卡并让其他选项卡监听 到它?
我有这些想法:
在初始化期间,选项卡询问使用 BroadcastChannel:“是否有主选项卡?”。如果收到答复,它将继续工作。如果它没有收到任何响应,那么它就会使自己成为一个主选项卡。
问题:
如果主选项卡在重循环内冻结,那么它将无法在短时间内响应,从而导致与服务器的2个打开连接和冲突,需要解决。
在初始化期间,选项卡将请求一些名为“
X
”或 smth 的字段。如果字段为空,则选项卡将创建该字段并分配一些值,然后它将使自己成为主选项卡。如果字段“X
”不为空,则选项卡将使自己成为从属选项卡。
问题:
如果两个选项卡同时初始化,可能会发生冲突:
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
结果,我遇到了冲突并打开了两个连接。
经过研究。
Halcyon 建议使用gist.github.com/neilj/4146038
中的代码。但我对这个解决方案并不满意,因为如果
Math.random()
将为 2 个不同的选项卡返回 2 个相同的数字,而它们将初始化,那么浏览器将调用
masterDidChange()
两次。浏览器最终会出现冲突和 2 个连接。然后 Dimitry Boger 建议阅读以下内容:
alpha.de/2012/03/javascript-concurrency-and-locking-the-html5-localstorage
。我更喜欢这个解决方案,但我仍然设法找到一种方法来打破它。
criticalSection()
。然后我发现了一个
wikipedia.org/wiki/Peterson's_algorithm
。我还没有找到打破这个锁定机制的方法,但是有一个问题。为了使该算法发挥作用,浏览器必须在执行之前知道确切的选项卡数量。因为如果它将初始化一个新选项卡,那么前一个选项卡可能会错过此事件并在新选项卡完成其自己之前启动其
criticalSection()
。因此,如果您不害怕 1024 个选项卡同时初始化和冻结它们,那么您可以使用任何此解决方案。但我需要一个防弹标签,所以我决定给予后端服务器
找到主选项卡的荣誉。
谢谢大家的帮助。
经过另一次研究。
帖子下面有防弹答案。它可以在没有后端服务器的情况下工作。
windowcontroller.js。
它正确处理竞争条件和超时。我认为它可以开箱即用,但我对其进行了一些修改以满足我的需求。
storage
事件与选项卡进行此通信:
https://developer.mozilla.org/en-US/docs/Web/API/Window/storage_event
在选项卡主控中:
window.localStorage('foo', 'bar')
在所有选项卡中:
window.addEventListener('storage', (event) => {
if(event.key === 'foo') {
// The foo localStorage key is updated on another tab,
// so now I can update this tab
}
})