
很久以前,在遥远的星系中,似乎出现了一项任务,用于同步Web播放器的浏览器选项卡,例如VK:有必要组织选项卡之间的数据交换,跟踪它们的编号并将任务分配给其中一些。 整个实现必须在客户端上完成。 收集了大量信息,并将其输入整篇文章中。
下面,我将描述解决此类问题的各种方法。
考虑最复杂的浏览器选项卡同步方式。
本地存储
localStorage-本地存储(窗口对象的属性),允许您访问本地
存储对象。 它可以在用户会话之间存储数据。 有一个类似的属性
-sessionStorage ,但它只存储页面会话持续时间内的数据。
使用
setItem方法将数据添加到存储中。
localStorage.setItem('key', 'value');
存储事件是在选项卡之间同步数据的理想选择;它是在localStorage或sessionStorage元素的值更改时生成的。
window.addEventListener('storage', function(event) { console.log(event.key); });
该事件在进行更改的选项卡上不起作用,但会在浏览器中域的其余选项卡上触发。
存储事件生成浏览器的localStorage和sessionStorage具有不同的存储级别:
- Chrome,FireFox和Opera〜5 MB。
- IE〜4.8 MB。
- iOS Safari,OS X Safari〜2.5 MB。
- Android〜5 MB。
缺点之一是可以注意到浏览器的存储量,当存储量满时,将不会记录新对象。
该方法在
Opera mini之外的所有浏览器中都适用。
发表讯息
postMessage是一种方法,可让您安全地发送跨域请求,即,彼此通信至来自不同域的Windows和iframe。
对于从主页通过iframe连接的外部小部件和服务的交互非常方便。
信息传输:
const win = window.frames.target; win.postMessage('send message', 'http://javascript.ru');
传输的数据可以是支持
克隆的任何对象(字符串,对象,数组,映射,日期...)。 但是IE仅支持字符串。
网址表示只有该来源的窗口可以接收消息。
要接收消息,该窗口必须预订onmessage事件。
window.addEventListener('message', function(event) { if (event.origin != 'http://javascript.ru') { return; } console.log(event.data); });
任何窗口都可以访问此方法以向其发送消息,而不管文档在窗口中的位置如何。 因此,请务必检查原点。
在IE中,
postMessage界面仅适用于iframe,而在标签页和窗口之间不起作用。
广播频道API
广播频道API提供了查看上下文(窗口,选项卡)之间的简单链接。
BroadcastChannel对象创建一个公共通道,使您可以接收发送给它的任何消息。 标签页,窗口,iframe可以订阅该频道并与其建立连接。
const bc = new BroadcastChannel('test_channel');
postMessage方法将消息发布到通道。 该参数是支持
克隆的类型。
bc.postMessage('This is a test message.');
发布消息时,消息事件将发送到连接到此通道的每个对象。
bc.addEventListener('message', function (e) { console.log(e); })
将消息发布到不同上下文的通道。该API非常简单;可以将其视为简单的消息总线。 但是该方法有一个严重的缺点:不支持
Safari和IE 。
乍一看,您会发现几种类似的数据传输方法(例如MessageChannel,WebSocket),但是每种方法都有特定的用途-
比较它们 。
网络工作者
这是一种允许脚本在与Web应用程序的主线程分离的后台线程中运行的机制。 它是使用js文件实现的,该文件包含在页面中,使用异步HTTP请求。
工作者非常适合执行繁重的计算操作,而不会降低用户界面的速度。
但是,通过同步,只有两种类型的工作人员可以提供帮助。
这是一种特殊的工作程序,可以从多个浏览器上下文中进行访问。 让我们为选项卡编写一个共享js文件,例如shared-worker.js。
const worker = new SharedWorker('shared-worker.js');
每个选项卡都可以通过worker.port与工作人员通信。 工作者的脚本也可以访问其端口。 每次选项卡连接到worker时,脚本中都会触发connect事件。
创建postMessage方法是将选项卡数据发送到共享工作器。
worker.port.postMessage('test message');
您可以使用message事件检索辅助数据。
worker.port.onmessage = function (e) { console.log(e.data); };
SharedWorker API中有一个连接事件,但没有断开事件,因此数据将无法在关闭的选项卡中自清理-它们将继续被视为已打开。 这不会导致错误,但是可以认为是缺陷或功能API。
仅适用于
Chrome和FF 。
这是一个由事件驱动的工作人员,可以监视,拦截和修改网络请求并对其进行缓存。
工人注册:
if ('serviceWorker' in navigator) { navigator.serviceWorker.register('service-worker.js') .then(function() { return navigator.serviceWorker.ready; }) .catch(function(error) { console.error('registration error : ', error); }); }
使用message事件,选项卡可以接收来自worker js文件的数据,并且syncTabState函数用于处理消息。
self.addEventListener('message', function(e){ const data = e.data; const tabId = e.source.id self.syncTabState(data, tabId); });
sendTabState函数旨在将消息发送到选项卡。
self.sendTabState = function(client, data){ client.postMessage(data); }
详细的用法和许多示例
在这里 。
所有Web工作人员均无权访问窗口和文档对象。
服务人员无法在
IE和Opera mini中工作 。
同步库
对于那些不想骑自行车并准备考虑现有解决方案的人来说,这是一种方法。
它们的缺点是这些库大多数都是通用的,因此它们并不总是适合于狭窄的解决方案。
总结
总而言之,让我们直观地比较一下浏览器支持的方法。

在需要将消息发送到潜在的多个窗口/选项卡或iframe的简单情况下,请使用LocalStorage,BroadcastChannel和PostMessage。
共享工作程序和服务工作程序是用于管理共享状态锁和共享文件的最合适的解决方案。
对于Web播放器的任务,由于支持IE,因此选择了LocalStorage。
我希望本文能帮助您选择正确的同步方法。
感谢
海报团队的帮助和支持!
二手文章: