Javascript 选项卡同步和服务器事件

问题描述 投票:0回答:3

我的申请需要一些帮助,对我的英语感到抱歉。

我正在开发一个网站的前端。最终的应用程序应该可以在很多选项卡上正常工作(单个浏览器中~100 个)。每个选项卡都需要侦听从服务器发送的一系列事件并动态更改其内容。

我使用Websocket实现了这个功能。由于打开连接非常昂贵。因此,我分配了一个主选项卡,它将侦听来自服务器的事件并使用 BroadcastChannel 将它们分发到其他选项卡。我还有以下问题:


如何从所有选项卡中选择一个主选项卡并让其他选项卡监听 到它?

我有这些想法:

1.使用广播频道。

在初始化期间,选项卡询问使用 BroadcastChannel:“是否有主选项卡?”。如果收到答复,它将继续工作。如果它没有收到任何响应,那么它就会使自己成为一个主选项卡。

问题:

如果主选项卡在重循环内冻结,那么它将无法在短时间内响应,从而导致与服务器的2个打开连接和冲突,需要解决。

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 个选项卡同时初始化和冻结它们,那么您可以使用任何此解决方案。但我需要一个防弹标签,所以我决定给予后端服务器

找到主选项卡的荣誉。

谢谢大家的帮助。


经过另一次研究。

帖子下面有防弹答案。它可以在没有后端服务器的情况下工作。

javascript events synchronization dom-events web-frontend
3个回答
1
投票

SharedWorker

可以用来解决问题。

它将使用专用的阻塞线程来进行其自身和其他浏览器上下文(选项卡/iframe)之间的所有通信。所以它可以用来同步不同的东西。

MDN 关于 SharedWorker 的文章


0
投票
我不久前遇到了这个问题。我从一个名为 Overture 的应用程序中找到了这个

windowcontroller.js

它正确处理竞争条件和超时。

我认为它可以开箱即用,但我对其进行了一些修改以满足我的需求。


0
投票
您可以通过

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 } })
    
© www.soinside.com 2019 - 2024. All rights reserved.