在同一域上的不同窗口之间进行通信[重复]

Posted

技术标签:

【中文标题】在同一域上的不同窗口之间进行通信[重复]【英文标题】:Communicating between different windows on the same domain [duplicate] 【发布时间】:2012-06-15 07:49:48 【问题描述】:

我正在构建一个执行大量客户端数据下载和处理的应用程序。通过在驻留在子域上的 iframe 中进行处理,数据处理与主应用程序隔离。正是这个 iframe 下载数据。通过 postMessage 进行通信。

一切都很好,除了它可能会更好。

如果用户打开额外的选项卡/窗口,应用程序当前会重新加载所有数据,甚至可能会重复处理工作,这不是问题,只是它会减慢一切速度并且页面加载时间会更长。

我想做的是让每个***选项卡/窗口只与一个处理 iframe 进行通信,如果原始窗口关闭,则可以恢复该 iframe。问题是,这些不是通过 javascript 打开的,而是通过普通浏览器方法打开选项卡中的链接,所以我无法获得对发送消息所需的 iframe 的引用。

我是否可以将 iframe 的窗口引用传递给其他选项卡,以便它们可以通过 postMessage 与之通信?这是否可以通过使用共享工作者以某种方式实现?

我意识到我可以使用共享工作器来完成整个处理任务,但这会有它自己的问题,因为数据来自第三方域,无法从工作器内部访问。

只需要与所有主流浏览器的最新版本兼容。

编辑:我刚刚发现 SharedWorker 尚未在 Firefox 中实现,所以我想这不会起作用。我还有其他方法可以实现吗?

编辑 2:我发现您可以使用:

var win = window.open('', 'my_window_name'); 

从任何其他窗口捕获对 iframe 的引用。但是,如果 iframe 尚不存在,则它将作为窗口打开。即使立即关闭,它也会导致闪烁并导致“弹出被阻止”消息,使其无法使用。

【问题讨论】:

我认为网络工作者不是一个选项,因为它只能在 IE 10 中工作;-) 使用html5本地存储,可以吗? @pahnin 这是一个想法。我会做一个实验。 @pahnin 我看不到将窗口引用转换为字符串并再次返回的方法。如果使用 SharedWorkers,这也是一个问题。 @SystemicPlural 将长期运行过程的结果和/或进度简单地存储在localStorage 中可能更容易(我认为这也是 pahnin 的意思)。然后您可以定期检查其状态,并在完成后显示结果。 window-to-string-reference-to-window 的东西听起来很脆弱和棘手。 【参考方案1】:

万一其他人发现了这个问题,我想出了一个解决方案。它有点hacky,需要进一步测试。但到目前为止,它正在发挥作用。如果需要,它可以跨域工作。

它结合了两种技巧。

首先是使用

remote_window = window.open("", "remote_window_name");

获取对窗口的引用。这是有效的,因为如果一个窗口已经以给定的名称打开,则返回一个对它的引用,而不是打开一个新窗口。

但是,如果 iframe 不存在,则会弹出一个新窗口。为了防止这种情况,使用本地存储。加载窗口/选项卡时,它会检查 localStorage 以查看是否有另一个页面已经具有共享 iframe。如果不是,它会插入 iframe 并在本地存储中设置一个标志以表示它可用。

作为最后放弃的手段,如果窗口仍然打开,则使用 try 块来关闭新打开的窗口。 try 块防止跨域错误。这意味着最坏的情况是用户看到一个窗口弹出并消失,或者他们将看到“启用弹出窗口”消息。我还没有设法在测试中触发它 - 这只是一种边缘情况。

try 
    if(store_window.location.href === "about:blank" )
        remote_window.close();
        remote_window = insertIfame();
    
 catch(err) 

添加了一个 onunload 事件,该事件会在页面关闭时删除标志。

还创建了一个不断刷新超时标志的 setInterval。我让它每秒运行 4 次;当加载第二个窗口/选项卡时,它会在尝试与其通信之前检查 iframe 标志是否未超时。这是一个很小的开销,但远低于我加载第二个 iframe 的成本。如果浏览器崩溃或 onunload 由于任何原因没有触发,这可以防止数据过期。我在检查超时时留有一点余地——目前是 1 秒——以防主窗口陷入循环。余地只是超时,而不是完全删除标志的卸载事件。

每次发送消息时都需要检查该标志,以防带有 iframe 的原始窗口已关闭。发生这种情况时,iframe 会重新插入到需要它的第一个打开的窗口中并重置标志。

发回消息很容易。只需使用 receiveMessage 的 event.source 属性 - 这指向发送窗口。

最后一个需要考虑的边缘情况是,如果主窗口关闭,而它的 iframe 是辅助窗口的中间进程。从理论上讲,这可以通过在 iframe 中使用 onunload 事件将消息发送回任何正在处理数据的窗口来处理。但我还没有实现它,它可能不会在页面卸载之前完成。处理它的另一种方法是在检查标志并重试的辅助窗口中设置超时,我可能会走这条路线,因为消息已经附加了超时。

【讨论】:

以上是关于在同一域上的不同窗口之间进行通信[重复]的主要内容,如果未能解决你的问题,请参考以下文章

如何在两个 Weblogic 域之间进行通信?

Cookie不会在同一域上的不同页面之间保留

在没有窗口参考的选项卡dom之间进行通信[重复]

不同选项卡中控制器之间的Angularjs通信[重复]

在同一主机上的不同网络中的 Docker 容器之间进行通信

在tablayout片段之间进行通信[重复]