Polling é um modelo pull em que clientes perguntam repetidamente; SSE e WebSockets mantêm uma conexão aberta para o servidor fazer push em tempo real. Escolher entre eles são, na verdade, três perguntas — em que direção os dados fluem, com que frequência mudam e que infraestrutura fica no meio do caminho — e a resposta honesta varia por feature, não por app.
Principais pontos
| Pergunta | Resposta |
|---|---|
| Short polling | Perguntar num timer — simples, amigável a cache, requests quase todas desperdiçadas |
| Long polling | O servidor segura a request até chegar dado — push simulado sobre HTTP puro |
| SSE | Um stream HTTP, eventos de texto servidor → cliente, reconexão automática embutida |
| WebSockets | Um socket, full-duplex, com suporte a binário — o protocolo é seu |
| A regra prática | Uma direção → SSE · duas direções → WebSockets · mudanças raras → polling está ótimo |
O código, lado a lado
// 1 · Short polling — pergunta num timer
setInterval(async () => {
const res = await fetch('/api/messages?since=' + lastId);
render(await res.json()); // quase sempre vazio — headers pagos mesmo assim
}, 2000);
// 2 · Server-Sent Events — um stream HTTP, o servidor envia eventos de texto
const events = new EventSource('/api/stream');
events.onmessage = (e) => render(JSON.parse(e.data)); // reconecta sozinho
// 3 · WebSocket — um socket, as duas direções
const ws = new WebSocket('wss://api.example.com/live');
ws.onmessage = (e) => render(JSON.parse(e.data));
ws.send(JSON.stringify({ type: 'typing' })); // o cliente também faz push
O que a maioria dos apps realmente entrega — uma camada de subscription que é dona do transporte por você:
// JavaScript / Node.js — Back4app JS SDK
// The polling replacement: subscribe once, receive pushes
const query = new Parse.Query('Message');
query.equalTo('room', 'general');
const subscription = await query.subscribe(); // WebSocket under the hood
subscription.on('create', (msg) => render(msg)); // pushed, not polled
// subscription.unsubscribe() when the screen closes // Flutter / Dart — Back4app Flutter SDK
// The polling replacement: subscribe once, receive pushes
final liveQuery = LiveQuery();
final query = QueryBuilder<ParseObject>(ParseObject('Message'))
..whereEqualTo('room', 'general');
final subscription = await liveQuery.client.subscribe(query); // WebSocket under the hood
subscription.on(LiveQueryEvent.create, (msg) => render(msg)); // pushed, not polled // iOS / Swift — Back4app Swift SDK
// The polling replacement: subscribe once, receive pushes
let query = Message.query("room" == "general")
let subscription = try await query.subscribe() // WebSocket under the hood
subscription.handleEvent { _, event in
if case .created(let msg) = event { render(msg) } // pushed, not polled
} // Android / Kotlin — Back4app Android SDK
// The polling replacement: subscribe once, receive pushes
val client = ParseLiveQueryClient.Factory.getClient()
val query = ParseQuery.getQuery<ParseObject>("Message")
query.whereEqualTo("room", "general")
val subscription = client.subscribe(query) // WebSocket under the hood
subscription.handleEvent(SubscriptionHandling.Event.CREATE) { _, msg ->
render(msg) // pushed, not polled
} Como cada técnica funciona
Short polling é um setInterval em volta de um fetch: perguntar a cada n segundos se algo mudou. Cada ciclo paga uma request/response HTTP completa — headers, auth, roteamento — geralmente para ouvir “nada ainda”, e o atraso médio de entrega é metade do intervalo mais um round trip.
Long polling move a espera para o lado do servidor: o cliente pergunta, o servidor segura a request aberta até chegar dado ou estourar um timeout, e o cliente pergunta de novo imediatamente. Aproxima o push sobre HTTP puro — a gambiarra da era Comet, com seus custos conhecidos (churn de reconexão, headers por request, cuidado com ordenação) catalogados na RFC 6202.
Server-Sent Events tornam permanente a resposta segurada: uma resposta HTTP com Content-Type: text/event-stream que nunca termina, pela qual o servidor escreve eventos UTF-8 (campos data:, event:, id:, retry:, conforme o padrão WHATWG). O EventSource do navegador a consome — e reconecta automaticamente, retomando via Last-Event-ID.
WebSockets saem do HTTP por completo: um handshake faz o upgrade da conexão (101 Switching Protocols, RFC 6455), e a partir daí os dois lados trocam frames de texto ou binários com ~2–14 bytes de overhead, full-duplex, até alguém fechar o socket. Capacidade máxima — e tudo acima do frame (formato das mensagens, acks, reconexão, retomada) é seu para projetar.
SSE vs. WebSockets vs. long polling vs. short polling
| Short polling | Long polling | SSE | WebSockets | |
|---|---|---|---|---|
| Direção | Pull | Push simulado | Servidor → cliente | Full-duplex |
| Protocolo | HTTP puro | HTTP puro | Stream HTTP puro | Protocolo próprio após o upgrade |
| Latência de entrega | intervalo/2 + RTT | ~RTT | ~RTT | ~RTT |
| Payloads | Qualquer | Qualquer | Só texto UTF-8 | Texto + binário |
| Reconexão automática | Trivial (próximo poll) | Loop de re-request | Embutida + Last-Event-ID | Você escreve |
| Atrito com proxy/firewall | Nenhum | Baixo | Baixo (ressalvas de buffering) | O upgrade pode ser removido |
| Estado no servidor | Nenhum | Requests seguradas | Streams abertos | Sockets presos a nós |
| Complexidade | Trivial | Moderada | Baixa | A mais alta |
| Ponto ideal | Mudanças raras | Fallback legado | Feeds, notificações, streams de IA | Chat, jogos, colaboração |
Quanto custa o polling? A matemática do overhead
A comparação que nenhuma página de ranking faz — 1.000 clientes num poll de 2 segundos versus os mesmos 1.000 em push:
1.000 clientes, polling de 2 s 1.000 clientes, push
→ 500 requests/segundo sustentadas → 0 requests em repouso
→ ~800 B de headers por ciclo → framing de evento SSE ~5 B
→ ~0,4 MB/s de puro imposto de headers → overhead de frame WebSocket 2–14 B
→ quase toda resposta vazia → bytes só fluem quando existe dado
→ atraso médio de entrega: 1 s + RTT → atraso de entrega: ~RTT
A lição corta dos dois lados. Push ganha de lavada quando as atualizações são frequentes e a latência importa. Mas se os dados mudam de hora em hora, aquelas 500 req/s nunca se materializam — um poll gentil (ou refetch ao focar) é amigável a cache, debugável com curl, compatível com serverless e livre de estado de conexão. Descartar o polling por completo é moda, não engenharia.
Reconexão: o diferencial silencioso
Conexões caem — trocas de célula, tampas de laptop, timeouts de inatividade de proxy (muitas vezes 30–120 s, e é por isso que streams SSE enviam keep-alives de comentário e WebSockets trocam frames de ping/pong). O que acontece em seguida é o que separa os transportes. O contrato do SSE resolve: o navegador tenta de novo com o atraso retry definido pelo servidor e apresenta Last-Event-ID, de modo que um servidor que mantém um buffer curto de eventos retoma o stream sem lacunas. Um WebSocket cru simplesmente fecha: reconexão com backoff exponencial, recuperação de mensagens perdidas e protocolo de retomada são todos código de aplicação — o item mais subestimado de “a gente só usa WebSockets”. De qualquer forma, um cliente offline por minutos precisa de catch-up (reexecutar a consulta base), não só de reconexão — transportes de push entregam deltas, e deltas pressupõem uma linha de base.
Por que o chat de IA faz streaming por SSE
Saída de modelo token a token é a carga perfeita para SSE: estritamente unidirecional, texto, em rajadas, sobre HTTP puro que todo proxy e CDN entende, com semântica de retomada para gerações interrompidas. É por isso que as APIs de LLM esmagadoramente transmitem completions como text/event-stream — e por isso o padrão vale conhecer além dos chatbots: feeds de progresso, logs de build e dashboards têm o mesmo formato. WebSockets entram nos produtos de IA na camada de voz, em que o usuário interrompe no meio do stream — no momento em que o cliente precisa responder, o imposto do duplex compra alguma coisa.
Escalando push: por que statefulness importa
Polling e SSE são HTTP comum para um load balancer; qualquer servidor responde qualquer request (o SSE segura um stream, mas mantém a semântica HTTP, exigindo apenas proxies sem buffering). WebSockets são estado: cada socket prende um cliente a um processo, então escalar horizontalmente significa balanceamento consciente de conexões, drenagem nos deploys e um backplane de pub/sub (comumente Redis) para que uma mensagem publicada no servidor A alcance sockets mantidos pelo servidor B. No HTTP/1.1, o SSE tem seu próprio footgun famoso — seis conexões por origem compartilhadas entre abas (o alerta do MDN) — aposentado pelo HTTP/2, em que os streams se multiplexam numa única conexão. Nada disso é exótico; tudo isso é o motivo de existirem camadas gerenciadas de tempo real.
Casos de uso comuns
- Feeds de notificações e tickers — uma direção, texto, frequente: o quintal do SSE.
- Streaming de respostas de IA — o caso matador atual do SSE; uma direção, texto em tokens, retomada em caso de queda.
- Chat e colaboração — mensagens fluem nas duas direções com baixa latência: WebSockets, normalmente via uma camada gerenciada.
- Dashboards ao vivo — push de resultados de consulta; na prática, uma subscription de live query, não um transporte feito à mão.
- Dados que mudam devagar — estoque que atualiza de hora em hora, telas de configurações: polling ou refetch ao focar, honestamente.
Qual transporte você deveria usar? Matriz de decisão
| Sua situação | Escolha |
|---|---|
| Só servidor → cliente (feeds, streams, progresso) | SSE |
| Cliente e servidor enviam em tempo real | WebSockets |
| Atualizações mais raras que a cada poucos minutos | Short polling / refetch ao focar |
| Proxies hostis, infraestrutura legada | Long polling como fallback |
| Payloads binários ou de alta frequência | WebSockets |
| Plataforma serverless, timeouts de função | Polling, ou SSE via hosts com suporte a streaming |
| ”Eu só quero dados ao vivo na tela” | Uma camada de live query que seja dona do transporte |
Limitações e trade-offs
- SSE é só texto e só de ida. Binário precisa de codificação; qualquer conversa cliente-para-servidor viaja em requests HTTP separadas — ótimo para acks, errado para chat.
- WebSockets colocam você no negócio de protocolos. Framing, acks, reconexão, retomada, backpressure: o transporte é fácil, o contrato em cima é o trabalho.
- A simplicidade do polling esconde um piso de latência. Nenhum ajuste escapa do atraso médio de intervalo/2; encurtar o intervalo só recompra o imposto de headers.
- Long polling é o pior dos dois em escala. Requests seguradas consomem capacidade de servidor como push, enquanto pagam overhead de reconexão por mensagem como pull — por isso ele sobrevive apenas como degrau de fallback.
- Todo transporte de push precisa da cooperação dos proxies. Buffering de stream quebra o SSE em silêncio; headers de upgrade removidos quebram WebSockets — teste através da infraestrutura real, não do localhost.
Transportes de tempo real no Back4app
O Back4app é uma plataforma open-source de Backend as a Service (BaaS) que combina banco de dados gerenciado, APIs REST e GraphQL geradas automaticamente, autenticação, armazenamento de arquivos e funções serverless com Cloud Code. A decisão de transporte é em grande parte absorvida pelas Live Queries: as abas de código acima se inscrevem numa consulta e recebem eventos por push sobre uma frota de WebSockets que a plataforma opera — conexões, reconexões, checagens de permissão e fan-out entre servidores incluídos — de modo que “SSE ou WebSockets?” vira um detalhe de implementação que você herda, não uma infraestrutura que você constrói. Onde uma cadência mais suave genuinamente cabe, a mesma consulta roda como um fetch comum no seu cronograma; fazer polling de uma consulta Parse e inscrever-se nela estão a uma linha de distância, o que torna o transporte certo por feature um refactor, não uma reescrita.
Perguntas frequentes
O que é melhor, SSE ou WebSockets?
Nenhum dos dois universalmente — a pergunta é a direção. SSE é a ferramenta mais simples quando os dados fluem num sentido só, do servidor para o cliente: HTTP puro, reconexão automática, funciona através de proxies comuns. WebSockets justificam sua complexidade extra quando o cliente também precisa enviar em tempo real — chat, jogos, edição colaborativa.
SSE é mais rápido que polling?
Em latência de entrega, decisivamente: os eventos chegam quando acontecem, enquanto o polling tem em média metade do intervalo de poll mais um round trip. Também é mais barato — uma conexão mantida em vez de um fluxo de ciclos request/response quase sempre vazios, cada um pagando o overhead completo de headers HTTP.
Quando devo usar long polling?
Como fallback, não como primeira escolha: ele existe para ambientes em que conexões persistentes falham — intermediários legados, proxies que removem o upgrade de WebSocket ou bufferizam streams. O servidor segura cada request aberta até chegar dado, o que aproxima o push ao custo de churn de reconexão e overhead de headers por request.
Quantas conexões SSE um navegador pode abrir?
Sobre HTTP/1.1, seis por origem — e o limite é compartilhado entre abas, um footgun documentado em que um dashboard aberto em sete abas trava silenciosamente. Sobre HTTP/2, a restrição passa a ser o número de streams concorrentes multiplexados numa única conexão (por padrão em torno de cem), o que na prática aposenta o problema.
SSE reconecta automaticamente?
Sim — e é o recurso que mais o distingue de WebSockets crus. O EventSource refaz sozinho conexões caídas, respeita um intervalo de retry definido pelo servidor e envia o ID do último evento recebido num header Last-Event-ID, para o servidor retomar o stream sem lacunas. Reconexão de WebSocket é código que você escreve.
SSE pode enviar dados binários?
Não — o stream é texto UTF-8 por especificação; payloads binários precisam ser codificados, com cerca de um terço de overhead de tamanho. WebSockets carregam frames binários nativamente, o que importa para áudio, protocol buffers e qualquer coisa que já seja compacta.
O que os apps de chat de IA usam para fazer streaming das respostas?
Server-Sent Events, quase universalmente: geração token a token é streaming de texto numa direção só, que é exatamente o formato do SSE — HTTP puro na saída, sem negociação de upgrade, retomada automática. WebSockets aparecem em produtos de IA só quando o cliente precisa interromper ou falar no meio do stream, como em interfaces de voz.
Qual é a ordem de fallback para recursos de tempo real?
Detecte o suporte e degrade: WebSocket onde o caminho permite, SSE onde só o push do servidor é necessário ou os upgrades falham, long polling como denominador comum mais baixo. Bibliotecas maduras de tempo real negociam essa escada automaticamente — uma das razões pelas quais sockets crus raramente são usados sem camada em produção.