Generator Functions, Iterator Helpers
Generator Functions e Iterator Helpers - as propostas mais importantes para processamento sob demanda que transformam como você programa em JavaScript e Node.js.
Por que isso é importante
Generator Functions e Iterator Helpers - as propostas mais importantes para processamento sob demanda que transformam como você programa em JavaScript e Node.js.
O que são Generator Functions?
As Generator Functions são funções especiais marcadas com um asterisco (*) que podem retornar múltiplos valores ao longo do tempo. Uma Generator Function pode retornar múltiplos resultados - por isso o nome "função geradora". Para gerar esses dados você usa a palavra-chave yield , que notifica quem está consumindo essa função geradora que um valor foi retornado.
Pela especificação, quem estiver consumindo essa função vai ficar chamando o método <code>.next()</code> dela, para saber se mais algum valor foi retornado ou deve parar a execução. Ou simplesmente você pode usar o iterator com o <code>for...of</code> do JavaScript e imprimir resultado por resultado.
A pergunta fundamental: Por que não arrays?
"Tá, mas para que você retornaria mais de um valor de uma função em JavaScript? Por que não só retornar um array com todos os itens dentro?" Essa é a maior dúvida entre desenvolvedores, então vamos entender o problema real.
A diferença está no conceito de processamento sob demanda . Quando você retorna um array, está carregando TODOS os dados na memória de uma só vez. Com generators, você processa item por item, criando uma verdadeira "linha de produção" onde cada etapa é executada conforme necessário.
A analogia da linha de produção
Pense em como funciona o processamento de um arquivo CSV: você lê a primeira linha do arquivo, transforma em JSON e usa o <code>yield</code> para falar: "Olha, essa linha está pronta! Quem estiver escutando, usa aí que eu vou para o próximo".
É como se fosse uma linha de produção: "Eu consegui um resultado aqui, eu mando para frente, já pego o próximo, mando para frente e já era". Esse "manda para frente" é o que fazemos com o uso da palavra-chave <code>yield</code> .
Como funciona o método .next()
Ao chamar uma função geradora, ela retorna um iterador com o método <code>.next()</code> , que serve para consumir os valores um por um. Cada chamada retorna um objeto com duas propriedades: value e done . Essa abordagem dá controle total sobre quando avançar para o próximo valor.
Iterando com for-of
Além de usar <code>.next()</code> manualmente, o JavaScript permite consumir iteradores usando a sintaxe <code>for...of</code> , que torna o código mais limpo e legível. Essa forma de iteração cuida automaticamente do <code>done</code> .
Por que não usar arrays?
Arrays carregam todos os dados de uma vez, o que pode ser inviável em cenários com múltiplos gigabytes de informação. Com generators, você processa item por item, evitando estouros de memória e melhorando a performance do sistema.
Processamento Sob Demanda na Prática
Imagine mover 2GB de dados entre bancos. Ao invés de usar um array com todos os dados, você pode usar generators para pegar 100 itens, processar e mover. Isso reduz o uso de memória e torna o sistema mais eficiente.
Generators com CSV
Uma aplicação prática: leitura de um arquivo CSV linha a linha. Com yield , é possível transformar cada linha em JSON e emitir esse dado para o consumidor. Isso simula uma linha de produção, onde cada item é tratado de forma isolada.
Iterator Helpers: A Evolução
A nova proposta Iterator Helpers traz os métodos comuns como <code>map</code> , <code>filter</code> , <code>reduce</code> e <code>take</code> para iteradores. Isso aproxima a experiência de trabalhar com arrays, mas aplicável a dados gerados sob demanda.
A evolução do JavaScript moderno
Node.js está se modernizando há muito tempo. Hoje em dia você não necessariamente precisa usar aquelas classes de Stream diretamente. Você pode passar um async generator para ele e ele já vai saber trabalhar. O código fica muito mais simples e elegante.
A primeira proposta que está disponível na maioria dos lugares que rodam JavaScript são os Iterator Helpers . Se fosse para resumir: é pensar que funções como <code>map</code> , <code>filter</code> e <code>reduce</code> , que temos em arrays, agora podem se aplicar para funções de processamento sob demanda.
Node.js já implementou as funções de <code>filter</code> , <code>map</code> e outras que vão estar disponíveis no JavaScript no futuro. Você pode trabalhar com <code>map</code> , <code>filter</code> , <code>take</code> e vários outros métodos, como se estivesse trabalhando com dados em memória, mas agora processando dados sob demanda.
Async Iterator Helpers
Versão assincrona dos helpers permite processar dados que dependem de awaits, como streams de dados ou requisições assíncronas. Você pode filtrar, transformar e consumir dados que chegam em momentos diferentes.
Exemplo Prático com Iterator Helpers
Suponha um iterador que gera nomes. Podemos aplicar <code>map</code> para transformar os dados, <code>filter</code> para selecionar e <code>take</code> para limitar resultados. Tudo isso sob demanda, sem criar listas intermediárias.
Lendo CSV de Forma Incorreta
Uma prática ruim é ler um arquivo grande e empilhar os dados em listas com <code>on('data')</code> . Embora funcione, isso coloca tudo em memória e pode quebrar com arquivos muito grandes, além de prejudicar o desempenho.
Streams e Transform
Streams resolvem isso usando uma abordagem de pipeline. A leitura via <code>Readable</code> , transformação via <code>Transform</code> e gravação com <code>Writable</code> garantem que cada pedaço é tratado e descartado antes do próximo chegar.
JSON por linha com Stream
Você pode transformar CSV em JSON-L (um JSON por linha) usando stream. Cada linha é convertida via biblioteca <code>csvtojson</code> , filtrada e salva isoladamente. Isso evita acúmulos em memória mesmo com arquivos grandes.
Diferenças entre Node.js e JavaScript puro
É importante entender a diferença entre o que está disponível no Node.js versus JavaScript puro. Quando você está trabalhando com async generators no JavaScript no momento atual, eles ainda não têm aquelas funções de <code>filter</code> e <code>map</code> nativamente.
A alternativa que o Node.js encontrou foi primeiro transformar numa Readable Stream e aí sim você tem esses métodos. Quando os Iterator Helpers forem aprovados 100% em JavaScript, e os Async Iterator Helpers entrarem também, não vamos precisar fazer esse <code>Readable.from()</code> .
Isso acontece porque o módulo Streams é parte do Node.js, e a sintaxe JavaScript que interpreta o código é parte do interpretador V8. Node.js se adiantou e adicionou os helpers em cima de streams, não em cima de async iterators.
O futuro da especificação
Por essas propostas estarem em estágio de desenvolvimento, pode ser que nas próximas versões do Node.js mude o funcionamento interno. Honestamente, é improvável que mude a API pública. Pode adicionar mais operadores, refinar aqui e ali, mas alterações que quebrem projetos existentes são difíceis de acontecer.
Por isso, use e abuse desses helpers e principalmente de funções de processamento sob demanda, como streams em Node.js e JavaScript em geral. Esse tipo de conhecimento vale para desenvolvedores de todos os níveis.
Evite Processamento em Lote
Guardar tudo em memória para só depois processar é um anti-padrão. Prefira pipelines de stream que processam e liberam os dados imediatamente. Isso é essencial em ambientes com limitações de memória ou tempo real.
Readable → Transform → Writable
Esse trio é a base do processamento em stream. Um Readable emite os dados, o Transform processa cada pedaço, e o Writable grava os dados transformados. Cada elemento é responsável por uma fase do fluxo.
Evite memória compartilhada
Evite estratégias que acumulam os dados esperando o término da leitura. Use callbacks ou streams para lidar com cada parte do caminho. Isso mantém o sistema performático e resiliente.
Usando o for await...of
Em funções assíncronas, o <code>for await...of</code> permite consumir iteradores que retornam Promises. Ideal para pipelines onde a origem dos dados ou transformações são assíncronas.
Combinações poderosas
Generator Functions + Iterator Helpers + Async Iterators + Streams = pipeline robusto e enxuto. Essa composição te dá controle total de processamento mesmo em dados massivos.
Otimize código com modernos recursos
Com os novos recursos do Node.js, evitar anti-padrões e promover pipelines desacoplados ficou mais fácil. Quanto mais linha de produção você simular, melhor será o desempenho da sua aplicação em escala.
Próximos passos e aplicação prática
Essas técnicas transformam completamente como você vai programar em JavaScript. Use essas funcionalidades para processar terabytes de dados sem travar suas aplicações, respeitando o ciclo de vida do ambiente em que esteja trabalhando.
Sempre pense em processamento sob demanda: divisão de dados em chunks pequenos, pipelines eficientes e liberação de memória a cada etapa. Essa é a essência do JavaScript moderno para aplicações de alta performance.
Checklist para Processamento Sob Demanda
Continue lendo
Bun 1.3: Por que esta atualização muda tudo em JavaScript
Entenda em detalhes tudo o que o Bun 1.3 traz, da revolução em performance até recursos que mudam o jogo do...
Aprender Node.js: Guia Completo para Iniciantes em 2026
Guia completo para aprender Node.js do zero em 2026. Entenda o que é, configure seu ambiente, e crie sua primeira...
Como criar seu próprio Server MCP do zero com ferramentas personalizadas
Construa seu próprio server MCP com múltiplas ferramentas, incluindo uma biblioteca de UI personalizada como a ShadCN
Como criar seu primeiro servidor HTTP com Node.js do zero
Como iniciar seu primeiro projeto em Node.js, entender os principais módulos e aprender os fundamentos para...