Это звучит как работа для SharedWorker .
Все ваши страницы подпишутся на него и будут ждать передачи ресурсов:
Ниже приведен код из демо live fiddle (исходные кадры StackSnippet не допускаются для запуска SharedWorkers.)
const script_content = document.getElementById('worker-script').textContent;
const script_url = URL.createObjectURL( new Blob( [ script_content ] ) );
// This should be the only one per page
const worker1 = new SharedWorker( script_url );
worker1.port.onmessage = (e) => console.log('worker1 received data', e.data);
// This would be an other page
const worker2 = new SharedWorker( script_url );
worker2.port.onmessage = (e) => console.log('worker2 received data', e.data);
<script id="worker-script" >
const ports = []; // we'll store all the connected ports here
onconnect = e => { / everytime a process connects
ports.push( e.ports[ 0 ] );
};
setInterval( () => {
const rand = Math.random(); // fetched data
// transmit it to all connected processes
ports.forEach( port => port.postMessage( rand ) );
}, 1000
);
</script>
Самая большая проблема с SharedWorker - это поддержка браузера. Вы не сможете использовать его в Safari.
Но теперь у нас есть BroadcastChannel
API , который позволяет взаимодействовать между различными процессами в одном домене и который может быть довольно многофайловым легко благодаря событию Storage.
Таким образом, вы можете попытаться настроить систему, которая будет работать так же, как SharedWorker, но более сложным способом.
Когда браузер подключается к одной из ваших страниц, он пытается присоединиться к BroadcastChannel или создает его.
Сначала он отправляет сообщение через BroadcastChannel, спрашивающее, есть ли кто-то подключенный.
Вот подтверждение концепции jsfiddle , поскольку, хотя StackSnippet странным образом разрешено запускать BroadcastChannels, их нулевое происхождение не позволит им поделиться ни с одним экземпляром ... Откройте эту ссылку на нескольких вкладках и посмотрим, как они все говорят друг другу.
Вот код скрипки в любом случае:
const my_id = Math.random();
let I_am_the_master = false;
let connections = ["me"];
const master_timeout = ImDaMasta();
const channel = new BroadcastChannel('demo');
channel.onmessage = e => {
console.log(e.data);
switch (e.data.type) {
case "newData":
onnewdatareceived(e.data.data);
break;
case "disconnect":
ondisconnect(e);
break;
case "connect":
onconnect(e);
break;
case my_id:
oninitresponse(e);
}
};
channel.postMessage({
type: 'connect',
_id: my_id
});
onbeforeunload = e => {
channel.postMessage({
type: 'disconnect',
index: connections.indexOf('me')
});
}
// set ourselves as the master process
function ImDaMasta() {
I_am_the_master = true;
return setInterval(() => {
const rand = Math.random();
channel.postMessage({
type: "newData",
data: rand
});
log("I'm the master and did post", rand);
}, 1000);
}
// when we receive new data from the master
function onnewdatareceived(data) {
log("I'm a slave and received", data);
}
// when an other process disconnected
function ondisconnect(e) {
connections.slice(e.data.index, 1);
if (connections[0] === "me") {
ImDaMasta();
}
}
// when an other process connects
function onconnect(e) {
connections.push('other');
if (I_am_the_master) {
channel.postMessage({
type: e.data._id,
connections
});
}
}
// when the master process handled our connection
function oninitresponse(e) {
I_am_the_master = false;
clearTimeout(master_timeout);
connections = e.data.connections;
connections[connections.length - 1] = "me";
}
// helper
function log(...args) {
_log.textContent = args.map(o => JSON.stringify(o)).join(' - ');
}