🚀 Oferta especial: 60% OFF no CrazyStack - Últimas vagas!Garantir vaga →
MÓDULO 1 - AULA 2

Yield e .next() na Prática

Controle manual vs automático. Dominando a arte do processamento controlado

🎯 O que você vai aprender

Pela especificação, quem estiver consumindo essa função vai ficar chamando o método .next() dela, para saber se mais algum valor foi retornado ou deve parar a execução. Ou simplesmente você pode usar o iterator com o for...of do JavaScript.

🎮 Controle Manual com .next()

🔧 Como Funciona o .next()

Ao chamar uma função geradora, ela retorna um iterador com o método .next(), 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.

next-method-control.js
// 📚 CONCEITO: Controle manual com .next()
// Pense numa linha de montagem onde VOCÊ decide quando avançar
function* dataProcessor() {
  yield 'Processando arquivo 1...';  // 🔄 Primeira etapa
  yield 'Processando arquivo 2...';  // 🔄 Segunda etapa  
  yield 'Processando arquivo 3...';  // 🔄 Terceira etapa
  return 'Todos os arquivos processados!'; // ✅ Resultado final
}

// 🎮 CONTROLE TOTAL: Você decide quando "apertar play"
const processor = dataProcessor();

// 🔄 EXECUÇÃO PASSO-A-PASSO
let result = processor.next(); // Pega o primeiro status
while (!result.done) {         // Enquanto não terminou...
  console.log('Status:', result.value); // Mostra progresso atual
  
  // ⏰ PAUSA CONTROLADA: Simula processamento assíncrono
  await new Promise(resolve => setTimeout(resolve, 1000));
  
  result = processor.next(); // 👆 SÓ avança quando você quiser!
}

console.log('Resultado final:', result.value);

// 💡 VANTAGEM: Ideal para operações que precisam de pausa entre etapas
// (rate limiting, processamento batch, progresso visual)

🔄 For...of: O modo automático

✅ Mais Simples e Limpo

Além de usar .next() manualmente, o JavaScript permite consumir iteradores usando a sintaxe for...of, que torna o código mais limpo e legível. Essa forma de iteração cuida automaticamente do done.

for-of-iteration.js
// 📚 CONCEITO: for...of - A forma "automática" de consumir
// Pense numa esteira rolante que você só observa passando
function* fibonacci(limit) {
  let a = 0, b = 1; // 🌱 Sementes da sequência
  
  while (a <= limit) {
    yield a;          // 📤 Entrega o número atual
    [a, b] = [b, a + b]; // 🔄 Calcula próximos (destructuring)
  }
}

// 🎯 FORMA AUTOMÁTICA: for...of cuida do .next() pra você
console.log('Sequência de Fibonacci até 100:');
for (const num of fibonacci(100)) {
  console.log(num); // 0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89
  // 💡 JavaScript automaticamente chama .next() até done: true
}

// 🔧 CONVERSÃO RÁPIDA: Spread operator pega todos de uma vez
const fibArray = [...fibonacci(20)];
console.log('Array:', fibArray); // [0, 1, 1, 2, 3, 5, 8, 13]

// ⚡ VANTAGEM: Código mais limpo, sem gerenciar .next() manualmente
// ⚠️ CUIDADO: for...of não dá controle sobre pausas entre iterações

♾️ Geradores Infinitos

🚀 Poder Ilimitado

Uma das características mais incríveis dos generators é poder criar sequências infinitas sem travar o sistema. Você controla quando parar!

infinite-generators.js
// 🔄 GERADOR INFINITO: Números crescentes sem fim
function* infiniteNumbers() {
  let i = 0;
  while (true) { // 🔄 Loop infinito (mas controlado!)
    yield i++;   // 📤 Entrega número atual e incrementa
  }
}

// 🎯 USO CONTROLADO: Você decide quando parar
console.log('=== TESTE: Apenas 5 números ===');
let count = 0;
for (const num of infiniteNumbers()) {
  console.log('Número:', num);
  count++;
  
  if (count >= 5) break; // 🛑 PARA quando quiser!
}

// 🔧 GERADOR INFINITO: IDs únicos
function* uniqueIdGenerator() {
  let id = 1;
  while (true) {
    yield `id_${id++}`; // 📤 Gera IDs únicos infinitamente
  }
}

// 💼 USO PRÁTICO: Sistema de IDs
const idGen = uniqueIdGenerator();
console.log('=== GERANDO IDs ÚNICOS ===');
console.log(idGen.next().value); // "id_1"
console.log(idGen.next().value); // "id_2"
console.log(idGen.next().value); // "id_3"

// 🎲 GERADOR INFINITO: Números aleatórios
function* randomNumbers(min = 0, max = 100) {
  while (true) {
    yield Math.floor(Math.random() * (max - min + 1)) + min;
  }
}

// 🎮 SIMULAÇÃO: Dados de um jogo
console.log('=== SIMULANDO DADOS ===');
let rolls = 0;
for (const dice of randomNumbers(1, 6)) {
  console.log(`Dado: ${dice}`);
  if (dice === 6) {
    console.log('🎉 Tirou 6! Parou o jogo.');
    break;
  }
  rolls++;
  if (rolls > 10) { // Segurança para não rodar infinito
    console.log('⏰ Limite de tentativas.');
    break;
  }
}

// 💡 VANTAGEM: Memória constante mesmo com infinitas possibilidades!

⚖️ Manual vs Automático: Quando usar cada um?

🎮 Controle Manual (.next())

Use quando:

  • Precisar pausar entre iterações
  • Rate limiting para APIs
  • Processamento batch controlado
  • Interface com progresso visual
  • Tratamento de erro por item

🔄 Automático (for...of)

Use quando:

  • Processamento contínuo
  • Transformação de dados simples
  • Iteração completa garantida
  • Código mais limpo e legível
  • Conversão para arrays
manual-vs-automatic.js
// 🔄 EXEMPLO PRÁTICO: Processamento de logs
function* processLogs(logs) {
  for (const log of logs) {
    // 🔍 Analisa cada log
    const parsed = {
      timestamp: new Date(log.time),
      level: log.level,
      message: log.msg,
      processed: true
    };
    
    yield parsed;
  }
}

const sampleLogs = [
  { time: '2024-01-01T10:00:00Z', level: 'info', msg: 'Sistema iniciado' },
  { time: '2024-01-01T10:01:00Z', level: 'error', msg: 'Falha na conexão' },
  { time: '2024-01-01T10:02:00Z', level: 'info', msg: 'Conexão restaurada' }
];

// 🎮 CONTROLE MANUAL: Para análise cuidadosa
console.log('=== ANÁLISE MANUAL (com pausa) ===');
const logProcessor = processLogs(sampleLogs);
let logResult = logProcessor.next();

while (!logResult.done) {
  const log = logResult.value;
  console.log(`[${log.level.toUpperCase()}] ${log.message}`);
  
  // ⚠️ PAUSA em erros para análise
  if (log.level === 'error') {
    console.log('🔴 ERRO DETECTADO! Pausando para análise...');
    await new Promise(resolve => setTimeout(resolve, 2000));
  }
  
  logResult = logProcessor.next();
}

// 🔄 AUTOMÁTICO: Para processamento rápido
console.log('\n=== PROCESSAMENTO AUTOMÁTICO ===');
for (const log of processLogs(sampleLogs)) {
  console.log(`✅ Processado: ${log.message}`);
}

🚀 Checkpoint: Dominando Controle

Método .next()For...of automáticoGeradores infinitosControle de fluxo

Agora você tem controle total sobre quando e como processar dados!