Como Usar Generators e Iteradores em JavaScript em Produção Já leu

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

O que são Iteradores?

Um iterador é um objeto que implementa dois métodos: next() e opcionalmente return() e throw(). O método next() retorna um objeto com duas propriedades: value (o valor atual) e done (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:

function criarIteradorNumeros(max) {
  let atual = 1;

  return {
    next() {
      if (atual <= 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 }

O Protocol Iterável e o Loop for...of

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

Vamos criar um objeto iterável customizado:

const minhaColecao = {
  dados: ['A', 'B', 'C'],

  [Symbol.iterator]() {
    let indice = 0;
    return {
      next: () => {
        if (indice < 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); // ['A', 'B', 'C']

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

Generators: Iteradores Simplificados

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

Um generator é fundamentalmente mais conciso. Veja como reescrever nosso exemplo anterior:

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
}

Generators com Lógica Complexa

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

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

Recebendo Valores em Generators

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

function* dialogo() {
  const resposta1 = yield 'Qual é seu nome?';
  console.log(`Olá, ${resposta1}!`);

  const resposta2 = yield 'Qual é sua idade?';
  console.log(`Você tem ${resposta2} anos.`);
}

const gen = dialogo();
console.log(gen.next().value);        // "Qual é seu nome?"
console.log(gen.next('Maria').value); // "Qual é sua idade?" (imprime: Olá, Maria!)
gen.next(25);                          // imprime: Você tem 25 anos.

Casos de Uso Reais

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:

function* lerLinhas(linhas) {
  for (const linha of linhas) {
    yield linha;
  }
}

const dados = ['linha 1', 'linha 2', 'linha 3', 'linha 4'];

for (const linha of lerLinhas(dados)) {
  console.log(linha); // processa uma por vez
}

Outra aplicação importante é criar pipelines de transformação:

function* range(inicio, fim) {
  for (let i = inicio; i < 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 => x * 2),
  x => x > 5
);

for (const num of resultado) {
  console.log(num); // 6, 8, 10, 12, 14, 16, 18
}

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 function* e yield, 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


Artigos relacionados