Maneiras de sincronizar as guias do navegador



Há muito tempo, em uma galáxia distante, uma tarefa parecia sincronizar as guias do navegador para um web player, como o VK: era necessário organizar a troca de dados entre as guias, rastrear seu número e atribuir tarefas a algumas delas. Toda a implementação teve que ser feita no cliente. Muitas informações foram coletadas e digitadas em um artigo inteiro.

Abaixo, descreverei várias maneiras de resolver esses problemas.

Considere as maneiras mais populares de sincronizar as guias do navegador em ordem crescente de complexidade.

Armazenamento local


localStorage - armazenamento local, uma propriedade do objeto de janela, permite acessar o objeto de armazenamento local. Ele pode armazenar dados entre as sessões do usuário. Existe uma propriedade semelhante - sessionStorage , mas ele armazena apenas dados durante a sessão da página.
Os dados são adicionados ao armazenamento usando o método setItem .

localStorage.setItem('key', 'value'); 

O evento de armazenamento é ideal para sincronizar dados entre guias; é gerado quando o valor do elemento localStorage ou sessionStorage é alterado.

 window.addEventListener('storage', function(event) { console.log(event.key); }); 

O evento não funciona na guia, que faz alterações, mas é acionado nas guias restantes do domínio no navegador.

Geração de eventos de armazenamento

Os navegadores têm níveis de armazenamento diferentes para localStorage e sessionStorage:

  • Chrome, FireFox e Opera ~ 5 MB.
  • IE ~ 4,8 MB.
  • Safari para iOS, Safari para OS X ~ 2,5 MB.
  • Android ~ 5 MB.

Entre as deficiências, nota-se o volume de armazenamento do navegador e, quando estiver cheio, um novo objeto não será gravado.
O método funciona em todos os navegadores, exceto no Opera mini .

Postar mensagem


postMessage é um método que permite enviar com segurança solicitações entre domínios, ou seja, se comunicar com janelas e iframes de domínios diferentes.
É muito conveniente para a interação de widgets e serviços externos conectados via iframe na página principal.
Transmissão de mensagem:

 const win = window.frames.target; win.postMessage('send message', 'http://javascript.ru'); 

Os dados transmitidos podem ser qualquer objeto que suporte a clonagem (sequência, objeto, matriz, Mapa, Data ...). Mas o IE suporta apenas strings.

URL indica que apenas janelas desta fonte podem receber mensagens.
Para receber mensagens, a janela deve se inscrever no evento onmessage.

 window.addEventListener('message', function(event) { if (event.origin != 'http://javascript.ru') { return; } console.log(event.data); }); 

Qualquer janela pode acessar esse método para enviar uma mensagem para ele, independentemente do local do documento na janela. Portanto, verifique a origem.

No IE, a interface postMessage funciona apenas com iframes e não funciona entre guias e janelas.

API do canal de transmissão


A API do Broadcast Channel fornece um link simples entre o contexto de visualização (janelas, guias). O objeto BroadcastChannel cria um canal comum que permite receber qualquer mensagem enviada a ele. Guias, janelas, iframes podem se inscrever no canal e estabelecer uma conexão com ele.

 const bc = new BroadcastChannel('test_channel'); 

O método postMessage publica uma mensagem no canal. O argumento é um tipo que suporta a clonagem .

 bc.postMessage('This is a test message.'); 

Quando uma mensagem é publicada, um evento de mensagem será enviado para cada objeto conectado a este canal.

 bc.addEventListener('message', function (e) { console.log(e); }) 


Publique uma mensagem em um canal para diferentes contextos.

A API é bastante simples; pode ser vista como um simples barramento de mensagens. Mas o método tem uma séria desvantagem: não há suporte para o Safari e o IE .

À primeira vista, você pode encontrar vários métodos semelhantes de transferência de dados (por exemplo, MessageChannel, WebSocket), mas cada um deles serve a um propósito específico - sua comparação .

Trabalhadores da Web


Este é um mecanismo que permite que um script seja executado em um encadeamento em segundo plano separado do encadeamento principal de um aplicativo Web. É implementado usando arquivos js, incluídos na página usando uma solicitação HTTP assíncrona.

Os funcionários são ótimos para executar operações de computação pesada sem diminuir a velocidade da interface do usuário.
Mas com a sincronização, apenas dois tipos de trabalhadores podem ajudar.

Trabalhador compartilhado


Esse é um tipo especial de trabalhador que pode ser acessado de vários contextos do navegador. Vamos escrever um arquivo js compartilhado para guias, por exemplo shared-worker.js.

 const worker = new SharedWorker('shared-worker.js'); 

Cada guia pode se comunicar com o trabalhador através do worker.port. O script do trabalhador também tem acesso às suas portas. Cada vez que a guia se conecta ao trabalhador, o evento de conexão é acionado no script.

 // shared-worker.js const connections = []; onconnect = function(e) { const port = e.ports[0]; connections.push(port); }; 

O método postMessage foi criado para enviar dados da guia para um trabalhador compartilhado.

 worker.port.postMessage('test message'); 

Você pode recuperar dados do trabalhador usando o evento de mensagem.

 worker.port.onmessage = function (e) { console.log(e.data); }; 

Há um evento de conexão na API SharedWorker, mas não há evento de desconexão e, portanto, os dados não poderão se auto-limpar em guias fechadas - eles continuarão sendo considerados abertos. Isso não levará a erros, mas pode ser considerado uma falha ou recurso da API.

Funciona apenas no Chrome e no FF .

Trabalhador de serviço


É um trabalhador orientado a eventos que pode monitorar, interceptar e modificar solicitações de rede e armazená-las em cache.
Registro de trabalhador:

 if ('serviceWorker' in navigator) { navigator.serviceWorker.register('service-worker.js') .then(function() { return navigator.serviceWorker.ready; }) .catch(function(error) { console.error('registration error : ', error); }); } 

Usando o evento de mensagem, as guias podem receber dados do arquivo js do trabalhador e a função syncTabState é usada para processar a mensagem.

 self.addEventListener('message', function(e){ const data = e.data; const tabId = e.source.id self.syncTabState(data, tabId); }); 

A função sendTabState foi projetada para enviar mensagens para guias.

 self.sendTabState = function(client, data){ client.postMessage(data); } 

Uso detalhado e muitos exemplos aqui .

Todos os trabalhadores da Web não têm acesso à janela e aos objetos do documento.

O trabalhador do serviço não funciona no IE e no Opera mini .

Bibliotecas de sincronização


Esta é uma maneira para quem não quer andar de bicicleta e está pronto para considerar as soluções existentes.


Sua desvantagem é que as bibliotecas são na sua maioria universais, portanto nem sempre são adequadas para soluções restritas.

Sumário


Para resumir, vamos comparar os métodos de suporte ao navegador visualmente.


Use LocalStorage, BroadcastChannel e PostMessage em casos simples, quando precisar enviar uma mensagem para potencialmente várias janelas / guias ou iframes.

Trabalhadores compartilhados e Operador de serviço são as soluções mais adequadas para gerenciar bloqueios de estado e arquivos compartilhados.

E para a tarefa com o web player, LocalStorage foi selecionado, pois há suporte para o IE.
Espero que este artigo tenha ajudado você a escolher o método de sincronização correto.

Agradeço à equipe de pôsteres por sua ajuda e apoio!

Artigos usados:

Source: https://habr.com/ru/post/pt422545/


All Articles