当前位置: 首页 > 知识库问答 >
问题:

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

薛欣德
2023-03-14

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

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

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

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

我是否可以将iframe的窗口引用传递给其他选项卡,这样它们就可以通过postmessage与它通信?这可以通过共享员工的方式实现吗?

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

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

编辑:我刚刚发现SharedWorker还没有在firefox中实现,所以我想这是行不通的。我还有别的办法可以做到这一点吗?

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

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

若要从任何其他窗口捕获对iframe的引用,请执行以下操作。但是,如果iframe还不存在,那么它会将其作为窗口打开。即使它立即关闭,它也会导致闪烁,并导致“弹出阻止”消息,使其无法使用。

共有1个答案

文寒
2023-03-14

万一别人发现了,我已经想出了解决办法。它有些古怪,需要进一步测试。但到目前为止,它是起作用的。如果需要,它可以跨域工作。

它使用了两种技巧的组合。

首先是利用

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事件将消息发送回任何正在处理数据的windows来处理。但我还没有实现它,它可能在页面卸载之前无法完成。另一种处理方法是在次要窗口中设置一个超时,检查标志并重试,我可能会走这条路,因为消息已经附加了超时。

 类似资料:
  • 我有两个网站,例如: foo.example.com bar.example.com 我想发送一些消息之间的网站,如果有打开在不同的标签。 有不同的可能方式: 邮件后传 SharedWorker 本地存储 但每一个都需要相同的来源或对Window.Opener的访问... 如果顶部域相同,则有解决方案浏览器端用于选项卡之间的通信?

  • 问题内容: 我有两个窗口:窗口A和窗口B。 窗口A和窗口B具有相同的域 窗口A和窗口B没有任何父窗口。 问题: 窗口A是否可以获得窗口B的引用? 使窗口A通知窗口B的最优雅方法是什么? (包括新的HTML5规范) 我知道这样做的两种方式: 服务器发送消息:窗口B经常询问服务器,窗口A是否已通知某些内容 通过本地数据(HTML5)进行消息传递:当窗口A要通知其更改本地数据的内容时,窗口B会定期检查本

  • 下面是一些示例代码: 这是我希望看到的输出:

  • 我正在寻找一种方法,如何在浏览器中的多个选项卡或窗口之间进行通信(在同一个域上,而不是CORS上)而不留下痕迹。有几种解决办法: 使用窗口对象 邮件后传 Cookies 本地存储 第一种可能是最糟糕的解决方案--你需要从你当前的窗口打开一个窗口,然后你只能在保持窗口打开的情况下进行交流。如果您在任何窗口中重新加载该页,则很可能会丢失通信。 第二种方法,使用postMessage,可能可以实现跨源通

  • 如果我知道一个Docker容器的IP地址,我就可以很容易地从另一个容器与它通信,但前提是它们在同一个网络中。 我的问题是,我如何与来自另一个网络的容器通信,为什么我不能访问同一台机器上的本地IP?我对网络解释感兴趣,为什么我可以从172.19.0.2访问172.19-0.1,但无法从172.20.0.1访问172.20-0.2。 让一个网络中的docker容器与另一个网络中的Docker容器进行通

  • 我想为谷歌地图上的每个标记创建一个自己的窗口。我尝试了这个: 不幸的是,只有第二个标记有一个包含的窗口。如果我单击第一个标记,那么带有的第二个标记的窗口就会弹出。我不明白为什么会发生这种情况。 我注意到,如果我为第二个标记和第二个窗口使用一个新变量,每个标记都有自己的窗口,如下所示: 但我完全不明白为什么我需要使用新的变量。为什么我不能覆盖旧的变量? 注意:这个问题是关于如何获取多个不同的info