选项卡或窗口之间的通信 [英] Communication between tabs or windows

查看:25
本文介绍了选项卡或窗口之间的通信的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在寻找一种如何在浏览器中的多个选项卡或窗口之间进行通信的方法(在同一域中,而不是 CORS) 不留痕迹.有几种解决方案:

I was searching for a way how to communicate between multiple tabs or windows in a browser (on the same domain, not CORS) without leaving traces. There were several solutions:

  1. 使用 window 对象
  2. postMessage
  3. cookies
  4. localStorage

第一个可能是最糟糕的解决方案 - 您需要从当前窗口打开一个窗口,然后只有在保持窗口打开的情况下才能进行通信.如果您在任何窗口中重新加载页面,您很可能会失去通信.

The first is probably the worst solution - you need to open a window from your current window and then you can communicate only as long as you keep the windows open. If you reload the page in any of the windows, you most likely lost the communication.

第二种方法,使用 postMessage,可能可以实现跨域通信,但它遇到与第一种方法相同的问题.你需要维护一个窗口对象.

The second approach, using postMessage, probably enables cross-origin communication, but it suffers the same problem as the first approach. You need to maintain a window object.

第三种方式,使用cookies,在浏览器中存储一些数据,这可以有效地看起来像向同一域内的所有窗口发送消息,但问题是你永远无法知道是否所有选项卡都读取了消息";在清理之前已经或没有.您必须实现某种超时才能定期读取 cookie.此外,您还受到最大 cookie 长度的限制,即 4 KB.

The third way, using cookies, store some data in the browser, which can effectively look like sending a message to all windows on the same domain, but the problem is that you can never know if all tabs read the "message" already or not before cleaning up. You have to implement some sort of timeout to read the cookie periodically. Furthermore you are limited by maximum cookie length, which is 4 KB.

第四个方案,使用localStorage,似乎克服了cookies的限制,甚至可以使用事件监听.已接受的答案中描述了如何使用它.

The fourth solution, using localStorage, seemed to overcome the limitations of cookies, and it can be even listen-to using events. How to use it is described in the accepted answer.

在 2018 年,接受的答案仍然有效,但现代浏览器有一个更新的解决方案,使用 BroadcastChannel.有关描述如何使用 BroadcastChannel 在选项卡之间轻松传输消息的简单示例,请参阅其他答案.

In 2018, the accepted answer still works, but there is a newer solution for modern browsers, to use BroadcastChannel. See the other answer for a simple example describing how to easily transmit message between tabs by using BroadcastChannel.

推荐答案

为此您最好使用 BroadcastChannel.请参阅下面的其他答案.但是,如果您仍然喜欢使用 localstorage 进行选项卡之间的通信,请这样做:

You may better use BroadcastChannel for this purpose. See other answers below. Yet if you still prefer to use localstorage for communication between tabs, do it this way:

为了在选项卡向其他选项卡发送消息时得到通知,您只需绑定存储"事件.在所有选项卡中,执行以下操作:

In order to get notified when a tab sends a message to other tabs, you simply need to bind on 'storage' event. In all tabs, do this:

$(window).on('storage', message_receive);

每当您在任何其他选项卡中设置 localStorage 的任何值时,都会调用函数 message_receive.事件侦听器还包含新设置到 localStorage 的数据,因此您甚至不需要解析 localStorage 对象本身.这非常方便,因为您可以在设置后立即重置该值,以有效清除任何痕迹.以下是消息传递函数:

The function message_receive will be called every time you set any value of localStorage in any other tab. The event listener contains also the data newly set to localStorage, so you don't even need to parse localStorage object itself. This is very handy because you can reset the value just right after it was set, to effectively clean up any traces. Here are functions for messaging:

// 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.
}

所以现在一旦你的标签绑定在 onstorage 事件上,并且你实现了这两个功能,你就可以简单地向其他标签调用广播消息,例如:

So now once your tabs bind on the onstorage event, and you have these two functions implemented, you can simply broadcast a message to other tabs calling, for example:

message_broadcast({'command':'reset'})

请记住,两次发送完全相同的消息只会传播一次,因此如果您需要重复消息,请为它们添加一些唯一标识符,例如

Remember that sending the exact same message twice will be propagated only once, so if you need to repeat messages, add some unique identifier to them, like

message_broadcast({'command':'reset', 'uid': (new Date).getTime()+Math.random()})

还要记住,广播消息的当前选项卡实际上并没有接收它,只会接收同一域中的其他选项卡或窗口.

Also remember that the current tab which broadcasts the message doesn't actually receive it, only other tabs or windows on the same domain.

您可能会问,如果用户在 removeItem() 之前的 setItem() 调用之后加载不同的网页或关闭他的选项卡会发生什么.好吧,根据我自己的测试,浏览器会暂停卸载,直到整个函数 message_broadcast() 完成.我测试在那里放了一些很长的 for() 循环,它仍然在等待循环完成后再关闭.如果用户在中间杀死选项卡,那么浏览器将没有足够的时间将消息保存到磁盘,因此这种方法在我看来是一种安全的方式来发送消息而没有任何痕迹.

You may ask what happens if the user loads a different webpage or closes his tab just after the setItem() call before the removeItem(). Well, from my own testing the browser puts unloading on hold until the entire function message_broadcast() is finished. I tested to put some very long for() cycle in there and it still waited for the cycle to finish before closing. If the user kills the tab just in-between, then the browser won't have enough time to save the message to disk, thus this approach seems to me like safe way how to send messages without any traces.

这篇关于选项卡或窗口之间的通信的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

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