Gerson Lázaro

Broadcast Channel API: Sincroniza Pestañas y Ventanas en Tiempo Real

Broadcast Channel API: Sincroniza Pestañas y Ventanas en Tiempo Real

Esta es la tercera entrega de la serie sobre APIs de Javascript. Al final del artículo encontrarás referencias actualizadas al resto de artículos de la serie a medida que sean publicados.

En este artículo estudiaremos la Broadcast Channel API, una herramienta potente y fácil de usar que permite la comunicación entre diferentes pestañas o ventanas de una aplicación web. Veámoslo paso a paso.

¿Para qué sirve la API de Broadcast Channel?

En la actualidad, es común que los usuarios mantengan abiertas varias pestañas o ventanas del navegador, incluso con diferentes páginas de un mismo dominio. Esto plantea desafíos interesantes desde la perspectiva del desarrollador. Por ejemplo, ¿qué sucede si un usuario carga varias páginas de una aplicación web en distintas pestañas o ventanas? Si cierra sesión en una de ellas, ¿deberían las demás cerrarse automáticamente? O si realiza un cambio en una página, ¿ese cambio debería reflejarse de inmediato en las demás?

Para este tipo de preguntas existe una solución sencillisima y que no requiere del servidor: BroadcastChannel API. Esta es una API propia de Javascript y disponible en practicamente todos los navegadores modernos que nos permite enviar y recibir mensajes entre diferentes contextos del navegador (aunque para simplicidad me referiré siempre a "pestañas", los contextos pueden ser cualquier ambiente del navegador que muestre un Document: pestañas, ventanas, frames, iframes, popups o aplicaciones web) y workers que compartan un mismo origin (protocolo, dominio y puerto).

¿Qué usos prácticos puedo darle a Broadcast Channel?

Con Broadcast Channel puedes transmitir cualquier mensaje entre diferentes pestañas del mismo origen, lo que abre muchas posibilidades. Algunos ejemplos:

  • Propagar configuraciones: Cuando un usuario cambia una configuración como el modo claro/oscuro o el idioma de un sitio web, podría propagarse esta configuración para ser aplicada inmediatamente en todas las pestañas abiertas.
  • Cambios de estado en una sesión: Cuando un usuario cierra su sesión en un sitio web, podría informar a todas las demás pestañas del mismo sitio para que la sesión se cierre en todas y así evitar inconsistencias.
  • Información realtime: En aplicaciones realtime puede utilizarse como una capa previa a la conexión al servidor, para sincronizar la información entre diferentes pestañas en el instante.
  • Alertas y notificaciones: Si un usuario realiza una acción que genera algún aviso, alerta o notificación, puede propagarse al resto de pestañas del mismo sitio para que el aviso sea informado en todas los demás.

¿Cómo usar Broadcast Channel API?

Su utilización es muy sencilla: Simplemente emitiremos un mensaje en una pestaña cuando lo consideremos necesario, y escucharemos en las demás para realizar alguna acción con ese mensaje. Para este ejemplo implementaremos un sitio con un botón que cambia el modo claro/oscuro del sitio y propaga el cambio automáticamente a todas las demás pestañas del mismo dominio.

Partiremos de un html básico:

<!DOCTYPE html>
<html>
    <head>...</head>
    <body class="light">
        <button class="demo__button">Cambiar Tema</button>
    </body>
</html>

Para simplificar, nuestra página solo tiene un botón para cambiar el tema. Al body le hemos asignado una clase light para indicar que está activo el modo claro. La idea es cambiar a dark cuando se pulse el botón, y de este modo cambiar el sitio a un modo oscuro. Los estilos por tanto serían:

body {
  height: 100%;
  width: 100%;
}

.light {
  background-color: white;
}

.dark {
  background-color: black;
}

Por supuesto los estilos podrían mejorarse muchisimo, pero para no salirnos del scope del artículo lo dejaremos así. Ahora, para añadir interactividad al botón y hacer que cambie el modo oscuro/claro del sitio, podemos jugar con la clase del body:


const toggleTheme = () => {
  const isDarkTheme = document.body.classList.contains('dark')
  const newTheme = isDarkTheme ? 'light' : 'dark'
  setTheme(newTheme)
}

const setTheme = (theme) => {
  document.body.className = theme
}

const toggleButton = document.querySelector('.demo__button')
toggleButton.addEventListener('click', toggleTheme)

De este modo cada vez que pulsemos el botón estaremos cambiando la clase del body y con ello, cambiando también el color de fondo del sitio. Pero por ahora estos cambios solo aplican a la pestaña con la que estamos interactuando. ¿Como propagarlo a las demás? En primer lugar, necesitamos crear una instancia del BroadcastChannel:

const channel = new BroadcastChannel('theme-switcher')

Ésta instancia recibe un único parámetro con el nombre del Channel, que debe ser el mismo entre la pestaña que emite y la que escucha.

El siguiente paso es enviar un mensaje. Para ello, hacemos uso de postMessage:

channel.postMessage('light')

De esta manera enviamos un mensaje a todas las pestañas del mismo origin que estén escuchando. En este caso estoy enviando un string, pero según la necesidad puede ser un objeto, un número, o cualquier elemento serializable. Entonces cuando un usuario pulse en el botón, cambiaremos el tema en la página actual, y enviaremos el postMessage para propagarlo a las demás. Para ello modificamos el método toggleTheme así:

const toggleTheme = () => {
    const isDarkTheme = document.body.classList.contains('dark')
    const newTheme = isDarkTheme ? 'light' : 'dark'
    setTheme(newTheme)
    channel.postMessage(newTheme)
}

Ahora nuestro sitio es capaz de cambiar su tema y de avisarle a los demás que también deben cambiarlo. Pero nos falta que las demás pestañas escuchen estos mensajes para que puedan replicar el comportamiento. Para ello hacemos uso del evento onmessage del channel que creamos previamente:

const channel = new BroadcastChannel('theme-switcher')

channel.onmessage = (event) => {
    setTheme(event.data)
}

Cuando un mensaje sea emitido en otra pestaña, el evento onmessage se disparará y llamará al mismo método setTheme que habíamos definido previamente, y así todas las pestañas del mismo origen que estaban abiertas recibirán el cambio de tema. El eventasociado trae en su propiedad datala información que se haya emitido en el postmessage.

La implementación completa quedaría de la siguiente manera:

const channel = new BroadcastChannel('theme-switcher')
const toggleButton = document.querySelector('.demo__button')

channel.onmessage = (event) => {
  setTheme(event.data)
}

const toggleTheme = () => {
  const isDarkTheme = document.body.classList.contains('dark')
  const newTheme = isDarkTheme ? 'light' : 'dark'
  setTheme(newTheme)
  channel.postMessage(newTheme)
}

const setTheme = (theme) => {
  document.body.className = theme
}

toggleButton.addEventListener('click', toggleTheme)

Si abrimos varias pestañas con este mismo código, todas ellas estarán en la capacidad de emitir y escuchar mensajes, y por tanto todas cambiarán el tema automáticamente cuando se pulse el botón en una de ellas.

Broadcast Channel API

Para ver esta implementación en funcionamiento, puedes abrir el demo funcional aquí. Abre la url en varias pestañas y luego cambia el tema en una de ellas. En este ejemplo encontrarás dos copias de la página, A y B, que contienen el mismo código en una ruta diferente del mismo dominio. La duplicidad es solo para demostrar que el comportamiento se mantiene aunque la ruta cambie (manteniendo por supuesto el mismo origen). El código de este ejemplo (que es el mismo aquí explicado, pero con unos estilos más completos) lo puedes encontrar aquí.

Compatibilidad

Esta API está disponible en las versiones actuales de todos los navegadores modernos del mercado: Chrome, Firefox, Safari, Opera y Edge. Para mayor detalle de compatibilidad recomiendo ver CanIUse.

Y tú, ¿en qué proyecto vas a usar broadcast channel?

Este artículo hace parte de una serie (en construcción) de artículos sobre APIs de Javascript. Actualmente la serie consta de las siguientes entradas:

Otros Artículos

Otros Artículos