Javascript 如何在Safari 10+;中使用BroadcastChannel API或类似工具;?

Javascript 如何在Safari 10+;中使用BroadcastChannel API或类似工具;?,javascript,safari,local-storage,broadcast-channel,Javascript,Safari,Local Storage,Broadcast Channel,问题: 我需要一个客户端Javascript解决方案(jQuery很好),其中一个浏览器窗口/选项卡中的事件可以广播到同一域中的其他窗口/选项卡。例如,如果在选项卡a中更新购物车,则会通知选项卡B和C,以便我们可以更新页面上的某些信息,或者通知用户页面已过时,或者类似的情况 我所尝试的: 这非常适合我的需要,但在IE 11或Safari中不起作用 所以我试着在任何地方使用广播频道API。它在IE中起作用,但在Safari中不起作用(我相信广播频道尚未定义) 然后我尝试了,它使用广播频道(如果可用

问题:

我需要一个客户端Javascript解决方案(jQuery很好),其中一个浏览器窗口/选项卡中的事件可以广播到同一域中的其他窗口/选项卡。例如,如果在选项卡a中更新购物车,则会通知选项卡B和C,以便我们可以更新页面上的某些信息,或者通知用户页面已过时,或者类似的情况

我所尝试的:

这非常适合我的需要,但在IE 11或Safari中不起作用

所以我试着在任何地方使用广播频道API。它在IE中起作用,但在Safari中不起作用(我相信广播频道尚未定义)

然后我尝试了,它使用广播频道(如果可用),否则使用
localStorage
伪造它。他们的演示页面在Safari中运行良好,但在我的网站上,我发现它在Safari 9中运行良好,而不是在10-12中(使用BrowserStack和一台运行Safari 12的真正Mac进行测试)。在调试他们的脚本时,当另一个选项卡中的
localStorage
发生更改时,应该触发的脚本似乎不会触发。但这实际上只是一个问题当您有
document.domain
集时,我会这样做

我相信这是一样的。但是,尽管Chrome在2012-2017年就出现了这个问题,但Safari显然是在2017年左右推出的

我在Safari中没有发现其他人讨论这个bug,但我可以很容易地证明这一点。打开使用相同
document.domain
值的两个选项卡并运行以下脚本:

表A:

$(window).on("storage", function (e) {
    alert('storage was modified');
});
表B:

localStorage.setItem("test", "123");
在Safari 9中,选项卡A将弹出警报。在Safari 10+中,它不会

如果我删除
document.domain
,它就会工作。请注意,我们在这些页面上使用的是
document.domain
,但在本例中,它们实际上位于同一个域中。但是,整个站点的其他场景需要
document.domain
,因此我无法删除它

我也试着看了看。它有一个事件系统,但它似乎只在同一个选项卡中工作(在任何浏览器中)。除非我遗漏了什么

那么,当您设置了
document.domain
时,是否有BroadcastChannel polyfill或类似的库在Safari 10+中真正起作用?
或其他方法

注:

  • 我知道BroadcastChannel和
    localStorage
    的“storage”事件只对当前选项卡以外的选项卡触发。这不是我的问题,事实上是我想要的
  • 我还看到过一些帖子,这些帖子让我相信,在Safari中,依靠
    localStorage
    的替代解决方案可能无法在私人浏览模式下工作。编辑:看起来这确实有效,但在我的测试中,它没有与任何其他选项卡共享本地存储,甚至没有与同一窗口中的其他私有选项卡共享本地存储。所以这帮不了什么忙。理想情况下,一个解决方案也能解释这一点,但在这一点上,我对Safari 10+中对我有用的任何东西都很满意。我确实在store.js项目中看到过一个例子,他们说他们在这种情况下是这样做的,所以这听起来至少是可能的
  • 我试着用
    setInterval
    来考虑其他方法,它每隔几秒钟检查
    localStorage
    是否有更新。即使从理论上讲,这似乎真的很粗糙和不可靠(你怎么知道什么时候所有的页面都“收到”了更新,这样你就可以清除它?)。你怎么知道什么时候用这种黑客方式而不是使用
    localStorage
    的首选方法?Safari 10+将报告它支持
    localStorage
    ,因此您无法真正检测到它,对吗?它“支持”它,只是不能正常工作

我找到了一个解决办法,但我将保留这个问题,因为我仍然希望看到更好的答案

最后,根据浏览器的不同,我在两种不同的消息传递方式之间切换

基本上,如果我使用的是Safari(您可以从中获得精简的vanilla JS版本)。这似乎适用于所有版本,即使您设置了
document.domain
。我认为它在本例中使用了indexDB,这似乎是完全的矫枉过正,但我似乎没有选择

在较新版本的Safari中,它也适用于Safari专用窗口。我已经在我的所有脚本中尝试了在私有模式下捕获Safari的旧版本,否则它会抛出错误


如果不是Safari,我会使用默认情况下使用
BroadcastChannel
,对于IE 11这样的情况,我会使用
localStorage

注意,只有在Safari中通信的窗口处于顶级时才有效,但如果一个窗口是iframe,则不起作用。由于Safari不支持本机广播频道,因此它只能使用本地存储。当在iframe中使用localStorage时,它不仅绑定到当前域的上下文,而且“双键”绑定到该域+window.top域。在需要时恢复到本地存储,因此无需使用其他library@NicholasHaley我相信我在尽可能地使用浏览器本地广播频道。我这样做的方式是,在两个插件之间,它基本上首先使用本机广播频道,然后返回到基于本地存储的解决方案,然后返回到基于indexDB的解决方案。@Roobot我有一个项目,我需要做类似的事情。在大多数情况下,“广播频道”库能够在本机广播频道支持不可用的情况下找到回退(localStorage或IndexedDB)。如果您的项目中需要更多的控制(如我所做的),那么第二个参数将获取一个对象,您可以在其中指定类型。需要说明的是,github.com/pubkey/broadcast-channe将尽可能使用本机广播频道。可能会简化您的代码。看:@NicholasHaley哦,真有趣!我想我从没见过医生的那部分。我看到它说“这个行为类似于BroadcastChannel API”