<h2>Iterables e o Protocolo de Iteração</h2>
<p>Um iterable é um objeto que implementa o protocolo iterável do JavaScript, permitindo ser percorrido em loops como <code>for...of</code>. Para ser iterable, um objeto deve ter um método <code>Symbol.iterator</code> que retorna um iterador — um objeto com um método <code>next()</code> que produz valores sequencialmente.</p>
<pre><code class="language-javascript">// Criando um iterable customizado
const intervalo = {
inicio: 1,
fim: 5,
[Symbol.iterator]() {
let atual = this.inicio;
return {
next: () => {
if (atual <= this.fim) {
return { value: atual++, done: false };
}
return { done: true };
}
};
}
};
for (const num of intervalo) {
console.log(num); // 1, 2, 3, 4, 5
}</code></pre>
<p>Entender esse protocolo é fundamental porque ele é a base de todas as iterações avançadas em JavaScript. Arrays, Strings, Maps e Sets já implementam isso nativamente. Quando você cria um iterable customizado, ganha controle total sobre como os dados são consumidos, ideal para estruturas de dados complexas ou infinitas.</p>
<h3>Diferença entre Iterable e Iterator</h3>
<p>Um iterable é <em>quem pode ser iterado</em>, enquanto um iterator é <em>quem controla a iteração</em>. O iterator mantém estado interno (qual é o próximo valor) e possui o método <code>next()</code>. Um mesmo iterable pode ter múltiplos iteradores independentes operando simultaneamente.</p>
<pre><code class="language-javascript">const numeros = [1, 2, 3];
const iter1 = numeros[Symbol.iterator]();
const iter2 = numeros[Symbol.iterator]();
console.log(iter1.next()); // { value: 1, done: false }
console.log(iter2.next()); // { value: 1, done: false }
console.log(iter1.next()); // { value: 2, done: false }</code></pre>
<h2>Generators: Simplificando a Iteração</h2>
<p>Generators são funções especiais que retornam iterators de forma muito mais simples. Usando a sintaxe <code>function*</code> e a palavra-chave <code>yield</code>, você escreve código iterativo de forma linear, sem precisar gerenciar manualmente o método <code>next()</code> e o estado.</p>
<pre><code class="language-javascript">function* contador(max) {
for (let i = 1; i <= max; i++) {
yield i;
}
}
const gen = contador(3);
console.log(gen.next()); // { value: 1, done: false }
console.log(gen.next()); // { value: 2, done: false }
console.log(gen.next()); // { value: 3, done: false }
console.log(gen.next()); // { value: undefined, done: true }
// Também funciona em for...of
for (const num of contador(3)) {
console.log(num); // 1, 2, 3
}</code></pre>
<p>O grande benefício é a legibilidade: você não precisa criar objetos com estruturas complexas. Generators mantêm o estado automaticamente, pausando na execução em cada <code>yield</code> e retomando de onde pararam. Isso é especialmente poderoso para processar grandes volumes de dados sem carregar tudo na memória.</p>
<h3>Generators com Comunicação Bidirecional</h3>
<p>Um aspecto avançado dos generators é a capacidade de receber valores através do método <code>next()</code>. Ao chamar <code>next(valor)</code>, esse valor é retornado da expressão <code>yield</code> anterior, permitindo comunicação bidirecional.</p>
<pre><code class="language-javascript">function* dialogoSimples() {
const resposta1 = yield "Qual seu nome?";
const resposta2 = yield Olá ${resposta1}, quantos anos você tem?;
console.log(${resposta1} tem ${resposta2} anos);
}
const gen = dialogoSimples();
console.log(gen.next().value); // "Qual seu nome?"
console.log(gen.next("Maria").value); // "Olá Maria, quantos anos você tem?"
gen.next(25); // "Maria tem 25 anos"</code></pre>
<h2>Generators Assíncronos: Iteração com Async/Await</h2>
<p>Um async generator combina generators com <code>async/await</code>, permitindo iterar sobre dados assíncronos de forma elegante. A sintaxe é <code>async function*</code> e pode usar <code>yield</code> com Promises, <code>await</code> ou ambos.</p>
<pre><code class="language-javascript">// Async generator que simula buscar dados de uma API
async function* buscarDados(ids) {
for (const id of ids) {
const resposta = await fetch(https://api.exemplo.com/usuario/${id});
const dados = await resposta.json();
yield dados;
}
}
// Consumindo com for await...of
(async () => {
for await (const usuario of buscarDados([1, 2, 3])) {
console.log(usuario.nome);
}
})();</code></pre>
<p>Async generators são ideais para processar streams de dados, como ler linhas de um arquivo, consumir eventos de um servidor, ou paginar resultados de uma API. O <code>for await...of</code> aguarda automaticamente cada Promise, mantendo o código sincronizado e legível.</p>
<h3>Casos Práticos: Paginação e Streams</h3>
<p>Um exemplo real é iterar sobre resultados paginados sem conhecer o total de páginas antecipadamente. O async generator busca a próxima página conforme necessário:</p>
<pre><code class="language-javascript">async function* paginarResultados(url) {
let pagina = 1;
while (true) {
const resposta = await fetch(${url}?page=${pagina});
const dados = await resposta.json();
if (!dados.items || dados.items.length === 0) break;
for (const item of dados.items) {
yield item;
}
pagina++;
}
}
// Uso simples
(async () => {
for await (const item of paginarResultados('https://api.exemplo.com')) {
console.log(item);
}
})();</code></pre>
<p>Esse padrão elimina a necessidade de fazer todas as requisições antecipadamente, economizando memória e permitindo cancelar a iteração a qualquer momento.</p>
<h2>Conclusão</h2>
<p>Iterables, generators e async generators formam uma progressão natural em JavaScript avançado. Começando com o protocolo iterável, você ganha controle fino sobre iterações customizadas. Generators simplificam drasticamente essa lógica sem sacrificar funcionalidade. Async generators, por sua vez, trazem elegância para operações assíncronas complexas, substituindo callbacks e promises aninhadas por código linear e legível. Dominar esses três conceitos permite escrever código mais eficiente, escalável e profissional.</p>
<h2>Referências</h2>
<ul>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Iteration_protocols" target="_blank" rel="noopener noreferrer">MDN - Iteration Protocols</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/function*" target="_blank" rel="noopener noreferrer">MDN - Generator Functions</a></li>
<li><a href="https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/for-await...of" target="_blank" rel="noopener noreferrer">MDN - for await...of</a></li>
<li><a href="https://javascript.info/generators" target="_blank" rel="noopener noreferrer">JavaScript.info - Generators</a></li>
<li><a href="https://eloquentjavascript.net/11_async.html" target="_blank" rel="noopener noreferrer">Eloquent JavaScript - Chapter on Iterators</a></li>
</ul>