W3docs

Funções Generator do JavaScript

Aprenda generators em JavaScript: sintaxe function*, yield e yield*, envio de valores com next(), return() e throw(), sequências infinitas e iteráveis.

Um generator é um tipo especial de função que pode pausar a si mesma no meio da execução, devolver um valor ao chamador e, em seguida, retomar exatamente de onde parou na próxima vez que for solicitada. Em vez de calcular tudo de antemão e retornar uma única vez, um generator produz uma sequência de valores de forma preguiçosa — um de cada vez, somente quando solicitado.

Essa ideia simples torna os generators a forma mais limpa em JavaScript de construir iteráveis personalizados, modelar sequências infinitas sem esgotar a memória e percorrer uma lógica de longa duração sob demanda. Este guia aborda a sintaxe function*, yield e yield*, comunicação bidirecional com next(), encerramento antecipado e os padrões práticos em que os generators se destacam.

Esta página é baseada em iteráveis e iteradores — se o protocolo de iterador for novo para você, leia isso primeiro.

Entendendo as Funções Generator

O Básico das Funções Generator

Uma função generator é declarada como uma função comum, mas com um asterisco após a palavra-chave function: function*. O asterisco é o que marca a função como um generator.

Chamar uma função generator não executa seu corpo. Em vez disso, ela retorna um objeto generator — um iterador que você conduz manualmente. Cada chamada ao seu método next() executa o corpo até o próximo yield, depois pausa e retorna { value, done }:

javascript— editable

O primeiro next() executa até o primeiro yield 'Hello' e pausa ali. O segundo retoma após essa linha e executa até yield 'World'. O terceiro retoma, não encontra mais instruções yield, chega ao fim da função e reporta done: true. Chamar next() novamente continuaria retornando { value: undefined, done: true }.

Como um objeto generator também é iterável, você pode consumi-lo com for...of, o operador spread ou desestruturação — todos os quais param automaticamente quando done se torna true:

javascript— editable
Nota

Um objeto generator só pode ser iterado uma vez. Após ser esgotado, for...of não produz nada. Chame a função generator novamente para obter um generator novo.

O valor de return de um generator

Um return dentro de um generator encerra a iteração e fornece o value final junto com done: true. Note que for...of ignora esse valor retornado — ele só vê os valores gerados por yield:

javascript— editable

Controlando o Fluxo com return() e throw()

Além de next(), um objeto generator expõe mais dois métodos que permitem ao chamador direcionar a execução externamente:

  • generator.return(value) força o generator a finalizar imediatamente, executando quaisquer blocos finally no caminho e retornando { value, done: true }.
  • generator.throw(error) injeta uma exceção no ponto yield atual, para que o generator possa capturá-la com try...catch — ou propagá-la se não o fizer.
javascript— editable

O bloco finally torna os generators um lugar organizado para liberar recursos (fechar um arquivo, desconectar um stream) mesmo quando a iteração é abandonada antecipadamente.

Padrões Avançados de Generator

Delegação com yield*

Quando um generator precisa produzir os valores de outro generator ou de qualquer iterável, use yield* (leia-se "yield-delegate") em vez de escrever um loop manual. Ele encaminha transparentemente cada valor da fonte delegada:

javascript— editable

Um detalhe útil: o valor da expressão de yield* é o valor de return do generator interno, o que permite compor generators e passar um resultado de volta ao externo:

javascript— editable

Enviando Valores para Generators

A comunicação com um generator é bidirecional. Uma expressão yield não apenas envia um valor para fora por meio de next(), mas também avalia para o que você passa para dentro na próxima chamada next(value). Isso transforma um generator em uma pequena corrotina interativa:

javascript— editable

O primeiro next() executa até o primeiro yield e retorna a pergunta; seu argumento é descartado porque ainda não há nenhum yield pausado para recebê-lo. O segundo next('Alice') retoma o yield pausado, de modo que a expressão se torna 'Alice' e é atribuída a name.

Aplicações Práticas dos Generators JavaScript

Construindo Iteráveis Personalizados

O uso mais comum dos generators no mundo real é tornar seus próprios objetos iteráveis. Defina [Symbol.iterator] como um método generator e qualquer for...of, spread ou desestruturação funcionará no objeto. Isso exige muito menos código repetitivo do que escrever um objeto iterador com um next() artesanal (veja Symbol type para entender o que é Symbol.iterator):

javascript— editable

Sequências Preguiçosas e Infinitas

Como um generator calcula cada valor somente quando solicitado, ele pode descrever uma sequência que é conceitualmente infinita sem jamais esgotar a memória. O exemplo clássico é um contador, mas a mesma abordagem serve para construir intervalos, geradores de ID ou streams de Fibonacci. Você combina isso com um auxiliar "take" que para após a quantidade necessária:

javascript— editable

Um generator de intervalo parametrizado é uma variante útil e reutilizável da mesma ideia:

javascript— editable

Gerenciando Operações Assíncronas

Historicamente, os generators eram usados para achatar o "callback hell": cada yield pausava em uma Promise, e um executor externo retomava o generator assim que a Promise era resolvida. O exemplo abaixo mostra a mecânica manual para que você possa ver o que acontece por baixo dos panos:

javascript— editable
Nota

Este é um executor manual simplificado. No código moderno, você escreveria isso com async/await, que a linguagem construiu diretamente em cima desse padrão de generator mais Promise. Para iteração assíncrona (transmissão de fragmentos ao longo do tempo) use async generators com async function* e for await...of.

Generators vs. Funções Comuns

AspectoFunção comumFunção generator
Declaraçãofunction fn()function* fn()
Ao chamá-laexecuta o corpo até o fimretorna um objeto generator, não executa nada ainda
Retornaum único valorum fluxo de valores via yield
Pode pausar?nãosim, em cada yield
É iterável?nãosim (funciona com for...of, spread)

Recorra a um generator quando precisar que valores sejam produzidos de forma preguiçosa ou sob demanda, que um objeto seja iterável, ou que uma sequência possa ser infinita. Para um cálculo simples de uso único, uma função comum é mais simples e mais rápida.

Conclusão

Os generators oferecem ao JavaScript uma forma limpa de produzir sequências de maneira preguiçosa, pausar e retomar a lógica, e fazer qualquer objeto funcionar com loops como for...of. Domine yield para emitir valores, yield* para delegar a outros iteráveis, e next()/return()/throw() para conduzir e controlar o fluxo — e você terá uma ferramenta que potencializa tudo, desde iteráveis personalizados até a sintaxe async/await construída sobre ela.

Prática

Prática
Qual é a função do caractere '*' antes da palavra-chave function nos generators do JavaScript?
Qual é a função do caractere '*' antes da palavra-chave function nos generators do JavaScript?
Was this page helpful?