2012-06-12 34 views
4

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

一切工作正常,但它可能会更好。

如果用户打开额外的选项卡/窗口,应用程序当前会重新加载所有数据,甚至可能会执行重复的处理工作,这不是一个问题,除了会减慢所有操作并减少页面加载时间。

我想要做的是每个顶级选项卡/窗口只与一个处理iframe进行通信,如果原始窗口关闭,可以恢复。麻烦的是,这些不是通过JavaScript打开,而是通过普通的浏览器方法打开标签中的链接,所以我无法获得发送消息所需的iframe的引用。

是否有反正我可以将iframe的窗口引用传递给其他选项卡,以便它们可以通过postMessage与它进行通信?在某种程度上可以通过共享工作人员来实现吗?

我意识到我可以在整个处理任务中使用共享工作人员,但由于数据来自第三方域,因此无法从工作人员中访问,所以这会产生问题。

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

编辑:我刚刚发现SharedWorker尚未在firefox中实现,所以我猜这是行不通的。任何其他方式我可以实现这一目标?

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

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

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

+0

我想网络工作者是不是一种选择,因为它只会在IE 10中工作;-) –

+0

使用html5 localstorage,可能是? – pahnin

+0

并使用javascript来检查 – pahnin

回答

2

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

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

的第一种是使用

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事件来处理,以便将消息发送回任何正在处理数据的窗口。但我还没有实现它,它可能无法完成页面卸载之前。处理它的另一种方法是通过在检查标志和重试的辅助窗口中超时,我可能会去这条路由,因为消息已经超时了。

相关问题