<h2>Iteradores: A Base de Tudo</h2>
<p>Um iterador é um objeto JavaScript que implementa o protocolo iterável, permitindo percorrer uma sequência de valores. Todo iterador possui um método <code>next()</code> que retorna um objeto com duas propriedades: <code>value</code> (o valor atual) e <code>done</code> (booleano indicando se chegou ao fim).</p>
<p>Para entender na prática, considere este exemplo: você precisa criar um iterador que gera números de 1 a 5. Implementamos através de um objeto com o método <code>Symbol.iterator</code>:</p>
<pre><code class="language-javascript">const minhaSequencia = {
valor: 1,
[Symbol.iterator]() {
return {
valor: this.valor,
next: () => {
if (this.valor <= 5) {
return { value: this.valor++, done: false };
}
return { done: true };
}
};
}
};
for (const num of minhaSequencia) {
console.log(num); // 1, 2, 3, 4, 5
}</code></pre>
<p>Essa implementação é funcional, mas verbosa. Generators resolvem exatamente esse problema oferecendo uma sintaxe muito mais limpa.</p>
<h2>Generators: Iteradores Simplificados</h2>
<p>Um generator é uma função especial que pode pausar sua execução e retomar depois. Você a declara com <code>function*</code> e usa <code>yield</code> para pausar. Quando chamada, retorna um iterador automaticamente.</p>
<p>Aqui está o mesmo exemplo anterior, mas muito mais elegante:</p>
<pre><code class="language-javascript">function* minhaSequencia() {
for (let i = 1; i <= 5; i++) {
yield i;
}
}
for (const num of minhaSequencia()) {
console.log(num); // 1, 2, 3, 4, 5
}</code></pre>
<p>A diferença é notável: o generator faz o mesmo trabalho com menos linhas e maior legibilidade. Quando você chama <code>minhaSequencia()</code>, não executa a função imediatamente — retorna um iterador. Cada vez que <code>next()</code> é chamado (implicitamente no <code>for...of</code>), a execução continua até o próximo <code>yield</code>.</p>
<h3>Dois Casos de Uso Cruciais</h3>
<p><strong>Gerando sequências infinitas</strong>: Você pode criar geradores que produzem valores infinitos sem criar arrays em memória:</p>
<pre><code class="language-javascript">function* infinito() {
let contador = 0;
while (true) {
yield contador++;
}
}
const gen = infinito();
console.log(gen.next().value); // 0
console.log(gen.next().value); // 1
console.log(gen.next().value); // 2</code></pre>
<p><strong>Delegando a outro generator</strong>: Use <code>yield*</code> para reutilizar generators dentro de generators:</p>
<pre><code class="language-javascript">function* geradorA() {
yield 1;
yield 2;
}
function* geradorB() {
yield* geradorA();
yield 3;
}
for (const valor of geradorB()) {
console.log(valor); // 1, 2, 3
}</code></pre>
<h2>Aplicações Práticas no Mundo Real</h2>
<h3>Processando Grandes Arquivos</h3>
<p>Imagine processar um arquivo CSV gigantesco linha por linha sem carregar tudo na memória:</p>
<pre><code class="language-javascript">function* lerArquivoLinhasPorLinhas(conteudo) {
const linhas = conteudo.split('\n');
for (const linha of linhas) {
yield linha.trim();
}
}
const dados = "nome,idade\nJoão,25\nMaria,30\nPedro,28";
for (const linha of lerArquivoLinhasPorLinhas(dados)) {
if (linha && !linha.startsWith('nome')) {
const [nome, idade] = linha.split(',');
console.log(${nome} tem ${idade} anos);
}
}</code></pre>
<h3>API com Paginação</h3>
<p>Generators simplificam muito o consumo de APIs paginadas. Você não precisa gerenciar estado manualmente:</p>
<pre><code class="language-javascript">async function* buscarPaginas(url) {
let pagina = 1;
let temProxima = true;
while (temProxima) {
const resposta = await fetch(${url}?page=${pagina});
const dados = await resposta.json();
yield dados.itens;
temProxima = dados.temProxima;
pagina++;
}
}
// Uso:
(async () => {
for await (const itens of buscarPaginas('https://api.exemplo.com/dados')) {
console.log('Processando', itens.length, 'itens');
}
})();</code></pre>
<p>Note o <code>async function*</code> e <code>for await...of</code> — essa é a forma moderna de trabalhar com generators assíncronos.</p>
<h3>Gerando IDs Únicos</h3>
<p>Um padrão muito prático é usar generators para gerar sequências de IDs:</p>
<pre><code class="language-javascript">function* gerarIds(prefixo = 'ID') {
let contador = 1;
while (true) {
yield ${prefixo}-${contador++};
}
}
const ids = gerarIds('USER');
console.log(ids.next().value); // USER-1
console.log(ids.next().value); // USER-2
console.log(ids.next().value); // USER-3</code></pre>
<h2>Conclusão</h2>
<p>Iteradores e generators são ferramentas poderosas que você usará constantemente em JavaScript moderno. <strong>Primeiro aprendizado</strong>: entender que todo objeto com <code>Symbol.iterator</code> é iterável, permitindo usar <code>for...of</code> e spread operator. <strong>Segundo aprendizado</strong>: generators são a forma elegante e prática de criar iteradores, economizando linhas de código e melhorando legibilidade. <strong>Terceiro aprendizado</strong>: generators assíncronos (<code>async function*</code> e <code>for await...of</code>) são essenciais para trabalhar com fluxos de dados assíncronos como APIs paginadas ou streams.</p>
<p>Dominar esses conceitos não é opcional — é fundamental para escrever código JavaScript eficiente e profissional.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Guide/Iterators_and_Generators" target="_blank" rel="noopener noreferrer">MDN: Iterators and Generators</a></li>
<li><a href="https://javascript.info/generators" target="_blank" rel="noopener noreferrer">JavaScript.info: Generators</a></li>
<li><a href="https://tc39.es/ecma262/#sec-generator-objects" target="_blank" rel="noopener noreferrer">ECMAScript Specification: Generator Objects</a></li>
<li><a href="https://eloquentjavascript.net/11_async.html" target="_blank" rel="noopener noreferrer">Eloquent JavaScript - Capítulo sobre Iteradores</a></li>
<li><a href="https://github.com/getify/You-Dont-Know-JS" target="_blank" rel="noopener noreferrer">You Don't Know JS Yet - Generators & Async Patterns</a></li>
</ul>