如何在Safari 10+中使用BroadcastChannel API或类似的东西? [英] How can I use the BroadcastChannel API or something similar in Safari 10+?

查看:460
本文介绍了如何在Safari 10+中使用BroadcastChannel API或类似的东西?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

问题:

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

我尝试过的事情:

BroadcastChannel API 非常适合我的需求,但是在IE 11或Safari中不起作用.

所以我尝试了 sysend.js ,如果可用,它将使用BroadCastChannel,否则会伪造它使用localStorage.他们的演示页面可以在Safari上正常运行,但是在我的网站上,我发现它可以在Safari 9上运行,但不能在10-12上运行(使用BrowserStack和一台运行Safari 12的真实Mac进行了测试).调试他们的脚本时,似乎存储事件更改其他选项卡中的localStorage时应该触发,但是根本不触发.但这实际上只是一个问题,我已经设置了document.domain .

我认为这与

选项卡B:

localStorage.setItem("test", "123");

在Safari 9中,标签A将弹出警报.在Safari 10+中,不会.

如果我删除了document.domain,它将起作用.请注意,我们在这些页面上使用了document.domain,但是在这种情况下,它们实际上位于同一域中.但是,该网站上的其他情况都需要document.domain,因此我无法将其删除.

我还尝试查看 store.js .它具有事件系统,但似乎只能在同一选项卡中使用(在任何浏览器中).除非我错过了什么.

那么,当您设置了document.domain时,是否存在任何可以在Safari 10+中实际运行的BroadcastChannel polyfill或类似的库?或通过其他任何方式?

注意:

解决方案

我找到了一种解决方法,但由于我仍然希望看到一个更好的答案,所以我将这个问题保留为开放状态.

作为最后的选择,我最终选择了两种不同的消息传递方式,具体取决于浏览器.

基本上,如果是Safari,我会使用 https://github.com/pubkey/broadcast-channel (您可以从 sysend.js ,默认情况下会使用BroadcastChannel并返回到localStorage,例如IE 11.

Problem:

I need a client-side Javascript solution (jQuery is fine) where an event in one browser window/tab can be broadcast to other windows/tabs on the same domain. For example, if a cart is updated in tab A, tabs B and C get notified so we can update some info on the page, or notify the user that page is stale, or something like that.

What I've tried:

The BroadcastChannel API fits my needs perfectly, but does not work in IE 11 or Safari.

So I tried this polyfill so I could use the BroadcastChannel API everywhere. It worked in IE, but not in Safari (I believe BroadcastChannel remained undefined).

I then tried sysend.js , which uses BroadCastChannel if it's available, otherwise fakes it using localStorage. Their demo page works fine in Safari, but on my site, I found it worked in Safari 9, but not 10-12 (tested using BrowserStack and one real Mac running Safari 12). Debugging their script, it seems the storage event that's supposed to fire when localStorage in a different tab is changed simply doesn't fire. But this is actually only a problem when you have document.domain set, which I do.

I believe this is the same as this old Chrome bug. But whereas Chrome had that issue from 2012-2017, Safari apparently introduced it around 2017?

I haven't found anyone else discussing this bug in Safari, but I can prove this pretty easily. Open two tabs that use the same document.domain value and run these scripts:

Tab A:

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

Tab B:

localStorage.setItem("test", "123");

In Safari 9, Tab A will pop the alert. In Safari 10+, it won't.

If I remove the document.domain, it works. Note that we are using document.domain on these pages, but they are actually on the same domain in this case. However document.domain is needed for other scenarios across the site, so I can't remove it.

I also tried looking at store.js. It has an event system, but it only seemed to work within the same tab (in any browser). Unless I'm missing something.

So, is there any BroadcastChannel polyfill or similar library that actually works in Safari 10+ when you have a document.domain set? Or any other way to do this?

Notes:

  • I'm aware that BroadcastChannel and the "storage" event for localStorage only fire for tabs other than the current one. That is not my issue, and is actually desirable to me.
  • I've also seen posts that make me believe an alternate solution relying on localStorage likely will not work in Private Browsing mode in Safari. EDIT: It appears this was fixed in Safari 11 so it does work, but in my tests it didn't share localStorage with any other tabs, even other Private tabs in the same window. So that's not much help. Ideally, a solution would account for this as well, but at this point I'd be happy with anything that worked in Safari 10+ for me. I did see an example in the store.js project where they said they made it so it would fallback to cookies in that case, so it sounds possible at least.
  • I tried to think about other ways to do this with a setInterval that checks the localStorage for updates every few seconds or something. Even in theory that seems really hacky and unreliable (how would you know when all pages have "received" the update so you can clear it out?). And how would you know when to do it this hacky way instead of one of the preferred methods using localStorage? Safari 10+ is going to report that it supports localStorage so you can't really feature detect it, right? It "supports" it, it just doesn't work correctly.

解决方案

I found a workaround, but I'll leave this question open because I'd still love to see a better answer.

As a last resort, I ended up toggling between two different ways of performing the messaging, depending on browser.

Basically, if it's Safari I use https://github.com/pubkey/broadcast-channel (you can get the minified vanilla JS version from https://github.com/pubkey/broadcast-channel/blob/master/dist/lib/browser.min.js). This seems to work in all versions even when you have a document.domain set. I think it uses indexDB in this case, which seems like total overkill, but I don't seem to have a choice.

It also works in Safari private windows in newer versions of Safari. I have try catches in place in all my script for older versions of Safari in private mode where it would otherwise throw errors.

If it's not Safari, I use sysend.js which uses BroadcastChannel by default and falls back to localStorage for cases like IE 11.

这篇关于如何在Safari 10+中使用BroadcastChannel API或类似的东西?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆