Formas de sincronizar las pestañas del navegador



Hace mucho tiempo, en una galaxia distante, una tarea parecía sincronizar las pestañas del navegador para un reproductor web, como VK: era necesario organizar el intercambio de datos entre pestañas, rastrear su número y asignar tareas a algunos de ellos. Toda la implementación tuvo que hacerse en el cliente. Se recopiló mucha información y se escribió en un artículo completo.

A continuación, describiré varias formas de resolver tales problemas.

Considere las formas más populares de sincronizar las pestañas del navegador en orden de complejidad creciente.

Almacenamiento local


localStorage : el almacenamiento local, una propiedad del objeto de ventana, le permite acceder al objeto de almacenamiento local. Puede almacenar datos entre sesiones de usuario. Existe una propiedad similar: sessionStorage , pero solo almacena datos durante la sesión.
Los datos se agregan al almacenamiento mediante el método setItem .

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

El evento de almacenamiento es ideal para sincronizar datos entre pestañas; se genera cuando cambia el valor del elemento localStorage o sessionStorage.

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

El evento no funciona en la pestaña, que realiza cambios, pero se dispara en las pestañas restantes del dominio en el navegador.

Generación de eventos de almacenamiento.

Los navegadores tienen diferentes niveles de almacenamiento para localStorage y sessionStorage:

  • Chrome, Firefox y Opera ~ 5 MB.
  • IE ~ 4.8 MB.
  • iOS Safari, OS X Safari ~ 2.5 MB.
  • Android ~ 5 MB.

Entre las deficiencias, se puede observar el volumen de almacenamiento del navegador, y cuando está lleno, no se grabará un nuevo objeto.
El método funciona en todos los navegadores, excepto Opera mini .

Publicar mensaje


postMessage es un método que le permite enviar de forma segura solicitudes de dominio cruzado, es decir, comunicarse entre sí a ventanas e iframes desde diferentes dominios.
Es muy conveniente para la interacción de widgets y servicios externos conectados a través de iframe desde la página principal.
Transmisión de mensajes:

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

Los datos transmitidos pueden ser cualquier objeto que admita la clonación (cadena, objeto, matriz, mapa, fecha ...). Pero IE solo admite cadenas.

Url indica que solo las ventanas de esta fuente pueden recibir mensajes.
Para recibir mensajes, la ventana debe suscribirse al evento onmessage.

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

Cualquier ventana puede acceder a este método para enviarle un mensaje, independientemente de la ubicación del documento en la ventana. Por lo tanto, asegúrese de verificar el origen.

En IE, la interfaz postMessage solo funciona con iframes y no funciona entre pestañas y ventanas.

Broadcast Channel API


Broadcast Channel API proporciona un enlace simple entre el contexto de visualización (ventanas, pestañas). El objeto BroadcastChannel crea un canal común que le permite recibir cualquier mensaje que se le envíe. Las pestañas, ventanas, iframes pueden suscribirse al canal y establecer una conexión con él.

 const bc = new BroadcastChannel('test_channel'); 

El método postMessage publica un mensaje en el canal. El argumento es un tipo que admite la clonación .

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

Cuando se publica un mensaje, se enviará un evento de mensaje a cada objeto conectado a este canal.

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


Publicar un mensaje en un canal para diferentes contextos.

La API es bastante simple; puede considerarse como un simple bus de mensajes. Pero el método tiene un serio inconveniente: no hay soporte para Safari e IE .

A primera vista, puede encontrar varios métodos similares de transferencia de datos (por ejemplo, MessageChannel, WebSocket), pero cada uno de ellos tiene un propósito específico: su comparación .

Trabajadores web


Este es un mecanismo que permite que un script se ejecute en un subproceso en segundo plano que esté separado del subproceso principal de una aplicación web. Se implementa utilizando archivos js, que se incluyen en la página mediante una solicitud HTTP asincrónica.

Los trabajadores son excelentes para realizar operaciones informáticas pesadas sin ralentizar la interfaz de usuario.
Pero con la sincronización, solo dos tipos de trabajadores pueden ayudar.

Trabajador compartido


Este es un tipo especial de trabajador al que se puede acceder desde varios contextos de navegador. Escribamos un archivo js compartido para pestañas, por ejemplo shared-worker.js.

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

Cada pestaña puede comunicarse con el trabajador a través de worker.port. El script del trabajador también tiene acceso a sus puertos. Cada vez que la pestaña se conecta al trabajador, el evento de conexión se activa en el script.

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

El método postMessage se creó para enviar datos de pestañas a un trabajador compartido.

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

Puede recuperar datos del trabajador utilizando el evento de mensaje.

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

Hay un evento de conexión en la API SharedWorker, pero no hay un evento de desconexión y, por lo tanto, los datos no podrán autolimpiarse en pestañas cerradas; continuarán considerándose abiertos. Esto no conducirá a errores, pero puede considerarse una falla o API de características.

Solo funciona en Chrome y FF .

Trabajador de servicio


Este es un trabajador impulsado por eventos que puede monitorear, interceptar y modificar solicitudes de red y almacenarlas en caché.
Registro de trabajadores:

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

Al usar el evento de mensaje, las pestañas pueden recibir datos del archivo js del trabajador y la función syncTabState se usa para procesar el mensaje.

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

La función sendTabState está diseñada para enviar mensajes a pestañas.

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

Uso detallado y muchos ejemplos aquí .

Todos los trabajadores web no tienen acceso a la ventana ni a los objetos del documento.

El trabajador de servicio no funciona en IE y Opera mini .

Bibliotecas de sincronización


Esta es una manera para aquellos que no quieren andar en bicicleta y están listos para considerar las soluciones existentes.


Su desventaja es que las bibliotecas son en su mayoría universales, por lo tanto, no siempre son adecuadas para soluciones limitadas.

Resumen


Para resumir, comparemos visualmente los métodos de soporte del navegador.


Use LocalStorage, BroadcastChannel y PostMessage para casos simples en los que necesite enviar un mensaje a múltiples ventanas / pestañas o iframes.

Shared Workers y Service Worker son las soluciones más adecuadas para administrar bloqueos de estado y archivos compartidos.

Y para la tarea con el reproductor web, se seleccionó LocalStorage, ya que hay soporte para IE.
Espero que este artículo te haya ayudado a elegir el método de sincronización correcto.

¡Agradezco al equipo de carteles por su ayuda y apoyo!

Artículos usados:

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


All Articles