O que é a BroadcastChannel API
A BroadcastChannel API e uma interface nativa dos browsers modernos que permite comunicação em tempo real entre múltiplas abas, janelas ou iframes do mesmo site. Sem biblioteca externa, sem WebSocket, sem nenhum servidor no meio.
Ela foi especificada pelo HTML Living Standard e esta disponível em todos os browsers modernos desde 2017 no Chrome e Firefox, e desde 2022 no Safari (versão 15.4). Hoje o suporte cobre mais de 95% dos browsers em uso no mundo, tornando a API segura para produção.
O problema que ela resolve e clássico: você tem um usuário logado em duas abas do mesmo sistema. Ele faz logout em uma aba. Como avisar a outra aba para também deslogar ou atualizar o estado? Por anos, a solução foi um hack com localStorage e o evento storage. A BroadcastChannel elimina essa gambiarra com uma interface muito mais limpa.
Como funciona
O mecanismo e simples: você cria um canal com um nome qualquer, e qualquer aba do mesmo site que criar um canal com o mesmo nome consegue enviar e receber mensagens por ele. E como um tópico de pub/sub dentro do próprio browser.
O escopo de um canal e limitado por origin (protocolo + domínio + porta). Abas de https://meusite.com não conseguem se comunicar com abas de https://outro.com. Isso garante isolamento de segurança automático, sem nenhuma configuração extra.
Por baixo dos panos, o browser usa memoria compartilhada entre contextos do mesmo processo (ou IPC para processos diferentes), tornando a comunicação extremamente rápida - muito mais rápida do que qualquer solução via servidor.
O nome do canal e case-sensitive. "MeuCanal" e "meucanal" são canais diferentes. Use sempre letras minúsculas e hifens para evitar confusão.
Principais recursos
A API e deliberadamente simples, com apenas o essencial para comunicação entre abas:
- postMessage(data) - envia uma mensagem para todas as outras abas no mesmo canal. A aba que envia não recebe a própria mensagem.
- onmessage - handler para receber mensagens. Recebe um objeto
MessageEventcom a propriedadedatacontendo o que foi enviado. - close() - fecha o canal e remove os listeners. Importante chamar quando o componente for destruído para evitar memory leaks.
- Serialization automática - qualquer objeto que passe pelo algoritmo de structured clone (objetos, arrays, Dates, Blobs, ArrayBuffers) pode ser enviado. Não precisa de JSON.stringify manual.
Ao contrario do hack do localStorage, a BroadcastChannel transmite qualquer tipo de dado serializavel, não apenas strings. Você pode enviar objetos complexos diretamente, inclusive com arrays, datas e blobs binários.
Como começar: uso básico passo a passo
Não ha instalação. A API esta disponível globalmente no browser. Veja o padrão mínimo:
// Criar o canal (mesmo nome em todas as abas)
const canal = new BroadcastChannel('meu-app');
// Enviar mensagem para outras abas
canal.postMessage({ tipo: 'logout', userId: 42 });
// Receber mensagens de outras abas
canal.onmessage = (event) => {
console.log('Recebi:', event.data);
// event.data = { tipo: 'logout', userId: 42 }
};
// Fechar quando não precisar mais
canal.close();Para usar no React, envolva em um hook para garantir que o canal e fechado quando o componente desmonta:
import { useEffect, useRef } from 'react';
function useBroadcastChannel(nome, onMensagem) {
const canalRef = useRef(null);
useEffect(() => {
canalRef.current = new BroadcastChannel(nome);
canalRef.current.onmessage = (e) => onMensagem(e.data);
return () => canalRef.current.close();
}, [nome]);
const enviar = (data) => canalRef.current?.postMessage(data);
return { enviar };
}
// Uso:
const { enviar } = useBroadcastChannel('sessão', (data) => {
if (data.tipo === 'logout') window.location.href = '/login';
});Sempre chame canal.close() quando o componente for destruído. Canais abertos sem uso consomem memoria e podem causar comportamentos inesperados se o componente for remontado.
Exemplo prático: logout sincronizado entre abas
Esse e o caso de uso mais clássico. O usuário tem três abas abertas do seu sistema. Ao fazer logout em uma delas, as outras precisam ser avisadas para redirecionar para a tela de login.
// auth.js - módulo compartilhado
const CANAL_AUTH = new BroadcastChannel('auth');
export function realizarLogout() {
// Faz o logout local
localStorage.removeItem('token');
sessionStorage.clear();
// Avisa todas as outras abas
CANAL_AUTH.postMessage({ tipo: 'logout' });
// Redireciona a aba atual
window.location.href = '/login';
}
// Ouve mensagens de outras abas
CANAL_AUTH.onmessage = (event) => {
if (event.data.tipo === 'logout') {
window.location.href = '/login';
}
};Esse padrão também funciona ao contrario: quando o usuário faz login em uma aba, você pode avisar as outras abas em branco para recarregar automaticamente e já entrar autenticadas. Isso cria uma experiência muito mais fluida, especialmente em sistemas com múltiplas telas abertas simultaneamente.
Outro uso prático: sincronizar o tema claro/escuro entre abas sem salvar no servidor. O usuário troca o tema em uma aba e todas as outras mudam instantaneamente.
Comparação com alternativas
Antes da BroadcastChannel, a solução dominante era escutar o evento storage do localStorage. Funcionava, mas tinha limitações serias:
- Só transmitia strings (precisava de JSON.stringify/parse)
- O evento não disparava na aba que gravou o valor
- Dependia de uma chave no localStorage, poluindo o armazenamento do usuário
- Comportamento inconsistente em modo PrivacyMode/Incógnito em alguns browsers
SharedWorker e outra alternativa mais poderosa, mas exige um arquivo JavaScript separado que roda como worker, o que adiciona complexidade de deploy e MIME type. Use SharedWorker se precisar de lógica mais complexa no meio (como filtrar ou transformar mensagens antes de distribuir).
Service Worker + postMessage funciona até offline, mas e significativamente mais complexo de implementar e requer HTTPS + service worker registrado. Para o caso simples de sincronização entre abas abertas, e excessivo.
Se você usa Zustand, Redux ou qualquer gerenciador de estado, pode criar um middleware que usa BroadcastChannel para sincronizar o estado inteiro entre abas. O pacote zustand/middleware/broadcastChannelStorage (da comunidade) já faz isso automaticamente.
Pontos positivos e limitações
Pontos positivos: API minimal e fácil de aprender, zero dependências, suporte a structured clone (não precisa serializar manualmente), funciona em Workers, SharedWorkers e iframes de mesma origem, e extremamente rápida (comunicação local, sem rede).
Limitações reais: Não funciona entre origens diferentes (mesmo domínio com portas diferentes são origens distintas). Não persiste mensagens: se a aba não estiver aberta no momento do envio, a mensagem e perdida. Não ha histórico nem replay. Não funciona offline ou entre sessions (fechar e abrir o browser não restaura estado do canal).
Nunca envie dados sensíveis (senhas, tokens completos) por BroadcastChannel sem uma estratégia de segurança. Embora o escopo seja limitado a mesma origin, extensões de browser mal-intencionadas podem interceptar as mensagens em alguns cenários.
Casos de uso reais
A BroadcastChannel resolve problemas bem específicos, e vale conhecer os perfis que mais se beneficiam:
- SaaS com múltiplas abas: sistemas de gestão onde o usuário abre pedido em uma aba e estoque em outra. Quando o pedido e confirmado, o estoque atualiza automaticamente.
- Dashboards em tempo real: quando o dado já vem via WebSocket em uma aba principal, a BroadcastChannel distribui para as outras abas sem duplicar a conexão com o servidor.
- Editores colaborativos light: sincronizar rascunhos ou seleção de texto entre janelas do mesmo usuário (diferentes do Operational Transform para múltiplos usuários).
- Carrinho de compras: e-commerces que querem que o contador do carrinho sincronize entre abas sem precisar de requests extras ao servidor.
Dicas e boas práticas
Use um objeto com campo tipo em todas as mensagens. Assim você pode ter múltiplas ações no mesmo canal sem criar um canal por ação.
Versione suas mensagens com um campo versão se o seu app pode estar com versões diferentes abertas ao mesmo tempo (ex: durante um deploy). Isso evita que uma aba antiga quebre ao receber uma mensagem com formato novo.
Para testar, abra duas abas no DevTools e execute const c = new BroadcastChannel('teste'); c.onmessage = e => console.log(e.data) em uma delas. Na outra, execute new BroadcastChannel('teste').postMessage('ola'). Você vera a mensagem aparecer instantaneamente na primeira aba.
Erros comuns de iniciantes: esquecer de fechar o canal (causa memory leaks), usar nomes diferentes entre abas (o canal simplesmente não conecta, sem erro), e tentar usar entre domínios diferentes (vai falhar silenciosamente, sem exceção).
Vale a pena?
Sim, definitivamente, se você ainda usa o hack do localStorage para sincronização entre abas. A migração e simples e o código fica muito mais limpo e expressivo.
Para quem esta começar um projeto novo, a BroadcastChannel deve ser a escolha padrão para comunicação entre abas. Só suba para SharedWorker ou Service Worker se precisar de lógica mais complexa ou persistência offline.
O próximo passo: abra o DevTools no seu projeto atual e procure por addEventListener('storage'. Se encontrar, você tem um candidato perfeito para migração para a BroadcastChannel API.
Comentários
Deixar um comentárioVocê precisa ter uma conta no CuritibaBlog para comentar.