JavaScript

Como Usar Generators e Iteradores em JavaScript em Produção

6 min de leitura

Como Usar Generators e Iteradores em JavaScript em Produção

O que são Iteradores? Um iterador é um objeto que implementa dois métodos: e opcionalmente e . O método retorna um objeto com duas propriedades: (o valor atual) e (booleano indicando se a iteração terminou). Iteradores permitem acessar elementos de uma coleção um por um, de forma controlada. Para entender melhor, vejamos um exemplo prático. Criaremos um iterador simples que percorre números de 1 a 3: Conclusão Os pontos-chave são: iteradores são a base do protocolo iterável, permitindo controle fino sobre iteração; generators simplificam enormemente essa implementação usando e , tornando o código mais legível; e ambos economizam memória ao processar dados sob demanda, não carregando tudo de uma vez. Domine esses conceitos para escrever código JavaScript mais elegante e eficiente. Referências MDN - Iterators and Generators ECMAScript Specification - GeneratorFunction You Don't Know JS Yet - Generators JavaScript.info - Generators

<h2>O que são Iteradores?</h2>

<p>Um iterador é um objeto que implementa dois métodos: <code>next()</code> e opcionalmente <code>return()</code> e <code>throw()</code>. O método <code>next()</code> retorna um objeto com duas propriedades: <code>value</code> (o valor atual) e <code>done</code> (booleano indicando se a iteração terminou). Iteradores permitem acessar elementos de uma coleção um por um, de forma controlada.</p>

<p>Para entender melhor, vejamos um exemplo prático. Criaremos um iterador simples que percorre números de 1 a 3:</p>

<pre><code class="language-javascript">function criarIteradorNumeros(max) {

let atual = 1;

return {

next() {

if (atual &lt;= max) {

return { value: atual++, done: false };

}

return { done: true };

}

};

}

const iterador = criarIteradorNumeros(3);

console.log(iterador.next()); // { value: 1, done: false }

console.log(iterador.next()); // { value: 2, done: false }

console.log(iterador.next()); // { value: 3, done: false }

console.log(iterador.next()); // { done: true }</code></pre>

<h2>O Protocol Iterável e o Loop for...of</h2>

<p>Um objeto é <strong>iterável</strong> quando implementa o método <code>Symbol.iterator</code>, que retorna um iterador. Essa é a base do protocolo iterável do JavaScript, permitindo usar <code>for...of</code> e spread operator. Arrays, Strings e Maps já são iteráveis nativamente.</p>

<p>Vamos criar um objeto iterável customizado:</p>

<pre><code class="language-javascript">const minhaColecao = {

dados: [&#039;A&#039;, &#039;B&#039;, &#039;C&#039;],

[Symbol.iterator]() {

let indice = 0;

return {

next: () =&gt; {

if (indice &lt; this.dados.length) {

return { value: this.dados[indice++], done: false };

}

return { done: true };

}

};

}

};

// Agora podemos usar for...of

for (const item of minhaColecao) {

console.log(item); // A, B, C

}

// E o spread operator

const array = [...minhaColecao];

console.log(array); // [&#039;A&#039;, &#039;B&#039;, &#039;C&#039;]</code></pre>

<p>A vantagem é que você controla completamente como a iteração funciona, permitindo lógica customizada sem precisar expor toda a estrutura interna.</p>

<h2>Generators: Iteradores Simplificados</h2>

<p>Generators são funções especiais declaradas com <code>function*</code> que pausam a execução com <code>yield</code> e retomam quando <code>next()</code> é chamado. Elas retornam um iterador automaticamente, eliminando a necessidade de implementar manualmente <code>next()</code> e <code>Symbol.iterator</code>.</p>

<p>Um generator é fundamentalmente mais conciso. Veja como reescrever nosso exemplo anterior:</p>

<pre><code class="language-javascript">function* gerador() {

yield 1;

yield 2;

yield 3;

}

const gen = gerador();

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()); // { done: true }

// Também funciona com for...of

for (const valor of gerador()) {

console.log(valor); // 1, 2, 3

}</code></pre>

<h3>Generators com Lógica Complexa</h3>

<p>Generators brilham quando você precisa de lógica mais sofisticada. Vejamos um exemplo prático: gerar números Fibonacci infinitamente:</p>

<pre><code class="language-javascript">function* fibonacci() {

let [a, b] = [0, 1];

while (true) {

yield a;

[a, b] = [b, a + b];

}

}

const fib = fibonacci();

console.log(fib.next().value); // 0

console.log(fib.next().value); // 1

console.log(fib.next().value); // 1

console.log(fib.next().value); // 2

console.log(fib.next().value); // 3

console.log(fib.next().value); // 5</code></pre>

<h3>Recebendo Valores em Generators</h3>

<p>O método <code>next()</code> pode receber argumentos que são retornados como valor de uma expressão <code>yield</code>. Isso permite comunicação bidirecional:</p>

<pre><code class="language-javascript">function* dialogo() {

const resposta1 = yield &#039;Qual é seu nome?&#039;;

console.log(Olá, ${resposta1}!);

const resposta2 = yield &#039;Qual é sua idade?&#039;;

console.log(Você tem ${resposta2} anos.);

}

const gen = dialogo();

console.log(gen.next().value); // &quot;Qual é seu nome?&quot;

console.log(gen.next(&#039;Maria&#039;).value); // &quot;Qual é sua idade?&quot; (imprime: Olá, Maria!)

gen.next(25); // imprime: Você tem 25 anos.</code></pre>

<h2>Casos de Uso Reais</h2>

<p>Generators são ideais para processar grandes volumes de dados sem carregar tudo na memória. Um exemplo clássico é ler um arquivo linha por linha:</p>

<pre><code class="language-javascript">function* lerLinhas(linhas) {

for (const linha of linhas) {

yield linha;

}

}

const dados = [&#039;linha 1&#039;, &#039;linha 2&#039;, &#039;linha 3&#039;, &#039;linha 4&#039;];

for (const linha of lerLinhas(dados)) {

console.log(linha); // processa uma por vez

}</code></pre>

<p>Outra aplicação importante é criar <strong>pipelines de transformação</strong>:</p>

<pre><code class="language-javascript">function* range(inicio, fim) {

for (let i = inicio; i &lt; fim; i++) {

yield i;

}

}

function* map(iteravel, funcao) {

for (const item of iteravel) {

yield funcao(item);

}

}

function* filter(iteravel, predicado) {

for (const item of iteravel) {

if (predicado(item)) yield item;

}

}

// Uso encadeado

const resultado = filter(

map(range(1, 10), x =&gt; x * 2),

x =&gt; x &gt; 5

);

for (const num of resultado) {

console.log(num); // 6, 8, 10, 12, 14, 16, 18

}</code></pre>

<h2>Conclusão</h2>

<p>Os pontos-chave são: <strong>iteradores</strong> são a base do protocolo iterável, permitindo controle fino sobre iteração; <strong>generators</strong> simplificam enormemente essa implementação usando <code>function*</code> e <code>yield</code>, tornando o código mais legível; e ambos economizam memória ao processar dados sob demanda, não carregando tudo de uma vez. Domine esses conceitos para escrever código JavaScript mais elegante e eficiente.</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://tc39.es/ecma262/#sec-generator-function-objects" target="_blank" rel="noopener noreferrer">ECMAScript Specification - GeneratorFunction</a></li>

<li><a href="https://github.com/getify/You-Dont-Know-JS/blob/2nd-ed/get-started/ch4.md" target="_blank" rel="noopener noreferrer">You Don&#039;t Know JS Yet - Generators</a></li>

<li><a href="https://javascript.info/generators" target="_blank" rel="noopener noreferrer">JavaScript.info - Generators</a></li>

</ul>

Comentários

Mais em JavaScript

Event Loop em JavaScript: Call Stack, Task Queue e Microtasks na Prática
Event Loop em JavaScript: Call Stack, Task Queue e Microtasks na Prática

Call Stack: O Coração da Execução O Call Stack é uma estrutura de dados que r...

Callbacks em JavaScript: O Padrão Original de Assincronismo: Do Básico ao Avançado
Callbacks em JavaScript: O Padrão Original de Assincronismo: Do Básico ao Avançado

Callbacks em JavaScript: O Padrão Original de Assincronismo O que é um Callba...

Como Usar Optional Chaining, Nullish Coalescing e Logical Assignment em JS em Produção
Como Usar Optional Chaining, Nullish Coalescing e Logical Assignment em JS em Produção

Optional Chaining (?.) O Optional Chaining é um operador que permite acessar...