Como funciona um stream
Stream é enviar dados em pedaços contínuos, à medida que ficam prontos, em vez de esperar tudo para mandar de uma vez. É assim que você assiste a um vídeo sem baixar o arquivo inteiro antes. O conteúdo chega aos poucos e já vai sendo usado.
A ideia
Sem stream:
[espera gerar tudo] -> [envia tudo] -> usuário só vê no fim
Com stream:
[pedaço] -> usuário já vê
[pedaço] -> mais um pouco
[pedaço] -> ...
O usuário começa a consumir antes do fim. Menos espera, menos memória usada.
Transferência em pedaços (chunked)
No HTTP, o servidor pode enviar sem saber o tamanho total, usando codificação em pedaços:
HTTP/1.1 200 OK
Transfer-Encoding: chunked
7
Olá mu
6
ndo!\n
0
Cada bloco traz seu tamanho. O bloco de tamanho 0 marca o fim. Útil quando o conteúdo é gerado em tempo real.
Backpressure: controle de fluxo
E se o produtor manda dados mais rápido do que o consumidor consegue ler? Sem controle, a memória enche. Backpressure é o consumidor sinalizar “calma, espera eu processar”:
Produtor --> dados --> Consumidor
Produtor <-- "pausa" -- Consumidor (buffer cheio)
Produtor <-- "ok" ----- Consumidor (pronto)
Assim os dois andam no mesmo ritmo, sem estourar a memória.
Exemplo em pseudocódigo
fonte.on("data", (pedaco) => {
const ok = destino.write(pedaco)
if (!ok) fonte.pause() // backpressure
})
destino.on("drain", () => fonte.resume())
Casos de uso
- Vídeo e áudio: assistir/ouvir enquanto baixa.
- Arquivos grandes: gerar e enviar um relatório enorme sem carregar tudo na memória.
- Dados ao vivo: logs em tempo real, cotações, respostas de IA token a token.
- Pipelines: ler de uma fonte, transformar e gravar em outra, pedaço por pedaço.
Vantagens
- Começa a entregar antes de terminar.
- Usa pouca memória, mesmo com dados gigantes.
- Bom para tempo real.
Desvantagens
- Mais complexo que enviar tudo de uma vez.
- Precisa tratar backpressure e erros no meio do caminho.
Stream é a base de quase tudo que é “ao vivo” ou grande demais para caber na memória. Pense em fluxo contínuo, não em blocos únicos.