Tom*_*s M 136 javascript browser html5 ipc broadcast-channel
我正在寻找一种方法,如何在浏览器中的多个选项卡或窗口之间进行通信(在同一个域上,而不是CORS),而不留痕迹.有几个解决方案:
第一个可能是最糟糕的解决方案 - 你需要从当前窗口打开一个窗口,然后只要你打开窗户就可以进行通信.如果您在任何窗口中重新加载页面,则很可能会丢失通信.
第二种方法,使用postMessage,可能启用跨源通信,但遇到与第一种方法相同的问题.您需要维护一个窗口对象.
第三种方式,使用cookie,在浏览器中存储一些数据,这可以有效地看起来像向同一域上的所有窗口发送消息,但问题是你永远不知道所有标签是否已经读过"消息"打扫干净.您必须实现某种超时以定期读取cookie.此外,您受限于最大cookie长度,即4KB.
使用localStorage的第四种解决方案似乎克服了cookie的限制,甚至可以使用事件进行监听.接受的答案中描述了如何使用它.
编辑2018:接受的答案仍然有效,但现代浏览器有一个更新的解决方案,使用BroadcastChannel.有关如何使用BroadcastChannel在选项卡之间轻松传输消息的简单示例,请参阅其他答案.
Tom*_*s M 130
编辑2018:您最好将BroadcastChannel用于此目的,请参阅下面的其他答案.但是,如果您仍然希望使用localstorage在选项卡之间进行通信,请执行以下操作:
为了在选项卡向其他选项卡发送消息时收到通知,您只需绑定"storage"事件即可.在所有标签中,执行以下操作:
$(window).on('storage', message_receive);
Run Code Online (Sandbox Code Playgroud)
message_receive每次在任何其他选项卡中设置localStorage的任何值时,都会调用该函数.事件监听器还包含新设置到localStorage的数据,因此您甚至不需要解析localStorage对象本身.这非常方便,因为您可以在设置后立即重置值,以有效清理任何痕迹.以下是消息传递的功能:
// use local storage for messaging. Set message in local storage and clear it right away
// This is a safe way how to communicate with other tabs while not leaving any traces
//
function message_broadcast(message)
{
localStorage.setItem('message',JSON.stringify(message));
localStorage.removeItem('message');
}
// receive message
//
function message_receive(ev)
{
if (ev.originalEvent.key!='message') return; // ignore other keys
var message=JSON.parse(ev.originalEvent.newValue);
if (!message) return; // ignore empty msg or msg reset
// here you act on messages.
// you can send objects like { 'command': 'doit', 'data': 'abcd' }
if (message.command == 'doit') alert(message.data);
// etc.
}
Run Code Online (Sandbox Code Playgroud)
所以现在,当你的标签绑定onstorage事件,并且你实现了这两个功能时,你可以简单地向其他标签调用消息,例如:
message_broadcast({'command':'reset'})
Run Code Online (Sandbox Code Playgroud)
请记住,两次发送完全相同的消息只会传播一次,因此如果您需要重复消息,请为它们添加一些唯一标识符,例如
message_broadcast({'command':'reset', 'uid': (new Date).getTime()+Math.random()})
Run Code Online (Sandbox Code Playgroud)
还要记住,广播消息的当前选项卡实际上并不接收它,只有同一域上的其他选项卡或窗口.
您可能会问,如果用户在removeItem()之前的setItem()调用之后加载不同的网页或关闭其选项卡会发生什么.好吧,根据我自己的测试,浏览器会暂停卸载,直到整个功能message_broadcast()完成.我测试了将一些非常长的for()循环放入其中并且它仍然等待循环结束然后关闭.如果用户只在中间杀死了标签,那么浏览器将没有足够的时间将消息保存到磁盘,因此这种方法对我来说似乎是安全的方式,如何发送没有任何痕迹的消息.欢迎评论.
use*_*ser 87
有一个专门用于此目的的现代API - 广播频道
它很简单:
var bc = new BroadcastChannel('test_channel');
bc.postMessage('This is a test message.'); /* send */
bc.onmessage = function (ev) { console.log(ev); } /* receive */
Run Code Online (Sandbox Code Playgroud)
消息不需要只是一个DOMString,可以发送任何类型的对象.
可能除了API清洁之外,它还是此API的主要优点 - 没有对象字符串化.
目前仅支持 Chrome和Firefox,但您可以找到使用localStorage的polyfill.
Nac*_*oma 36
对于那些寻找不基于jQuery的解决方案的人来说,这是Thomas M提供的解决方案的简单JavaScript版本:
window.addEventListener("storage", message_receive);
function message_broadcast(message) {
localStorage.setItem('message',JSON.stringify(message));
}
function message_receive(ev) {
if (ev.key == 'message') {
var message=JSON.parse(ev.newValue);
}
}
Run Code Online (Sandbox Code Playgroud)
sof*_*var 16
Checkout AcrossTabs - 跨源浏览器选项卡之间的轻松通信.它结合使用postMessage和sessionStorage API,使通信变得更加容易和可靠.
有不同的方法,每种方法都有自己的优点和缺点.让我们讨论每个:
优点:
缺点:
优点:
缺点:
每次HTTP请求(HTML,图像,JavaScript,CSS等)都会将数据发送回服务器 - 增加客户端和服务器之间的流量.
通常,允许以下内容:
优点:
localStorage.缺点:
localStorage,tt适用于同源策略.因此,存储的数据只能在同一个来源上使用.优点:
缺点:
targetOrigin传递给消息侦听器的数据执行和完整性检查.PostMessage + SessionStorage的组合
使用postMessage在多个选项卡之间进行通信,同时在所有新打开的选项卡/窗口中使用sessionStorage来持久传递数据.只要选项卡/窗口保持打开状态,数据就会保留.因此,即使开启者选项卡/窗口关闭,打开的选项卡/窗口也会在刷新后获得整个数据.
我为此编写了一个JavaScript库,名为AcrossTabs,它使用postMessage API在跨源选项卡/窗口和sessionStorage之间进行通信,以便在它们存在时保持打开的选项卡/窗口标识.
jcu*_*bic 11
我创建了一个库sysend.js 用于在浏览器选项卡和 windows 之间发送消息。该库没有任何外部依赖项。
您可以使用它在同一浏览器和域中的选项卡/窗口之间进行通信。该库使用 BroadcastChannel(如果支持)或来自 localStorage 的存储事件。
API 非常简单:
sysend.on('foo', function(data) {
console.log(data);
});
sysend.broadcast('foo', {message: 'Hello'});
sysend.broadcast('foo', "hello");
sysend.broadcast('foo', ["hello", "world"]);
sysend.broadcast('foo'); // empty notification
Run Code Online (Sandbox Code Playgroud)
当您的浏览器支持 BroadcastChannel 时,它会发送一个文字对象(但它实际上是由浏览器自动序列化的),如果不支持,则首先将其序列化为 JSON,然后在另一端反序列化。
最近的版本还有一个帮助 API 来创建跨域通信的代理(它需要目标域上的单个 HTML 文件)。
这是一个演示。
新版本还支持跨域通信,如果proxy.html在目标域中包含一个特殊文件并proxy从源域调用函数:
sysend.proxy('https://target.com');
Run Code Online (Sandbox Code Playgroud)
(proxy.html 是一个非常简单的 HTML 文件,库中只有一个脚本标签)。
如果你想要双向通信,你需要在其他域上做同样的事情。
注意:如果您将使用 localStorage 实现相同的功能,则 Internet Explorer 中存在问题。存储事件被发送到同一个窗口,它触发事件,对于其他浏览器,它只被其他选项卡/窗口调用。
有一个很小的开源组件可以在相同来源的标签/窗口之间进行同步/通信(免责声明 - 我是其中一个贡献者!)localStorage.
TabUtils.BroadcastMessageToAllTabs("eventName", eventDataString);
TabUtils.OnBroadcastMessage("eventName", function (eventDataString) {
DoSomething();
});
TabUtils.CallOnce("lockname", function () {
alert("I run only once across multiple tabs");
});
Run Code Online (Sandbox Code Playgroud)
https://github.com/jitbit/TabUtils
PS我冒昧地推荐它,因为当事件几乎同时发生时,大多数"lock/mutex/sync"组件都在websocket连接上失败
| 归档时间: |
|
| 查看次数: |
69524 次 |
| 最近记录: |