W3docs

Funzioni Generator in JavaScript

Impara i generator JavaScript: sintassi function*, yield e yield*, invio di valori con next(), return() e throw(), sequenze infinite lazy e iterabili personalizzati.

Un generator è un tipo speciale di funzione che può mettere in pausa se stessa nel mezzo dell'esecuzione, restituire un valore al chiamante e poi riprendere esattamente da dove si era fermata la volta successiva che si chiede altro. Invece di calcolare tutto in anticipo e restituire una sola volta, un generator produce una sequenza di valori in modo lazy — uno alla volta, solo quando richiesto.

Questa sola idea rende i generator il modo più pulito in JavaScript per costruire iterabili personalizzati, modellare sequenze infinite senza esaurire la memoria, e scorrere logiche a lunga esecuzione su richiesta. Questa guida copre la sintassi function*, yield e yield*, la comunicazione bidirezionale con next(), la terminazione anticipata e i pattern pratici in cui i generator eccellono.

Questa pagina si basa su iterabili e iterator — se il protocollo iterator è nuovo per te, leggilo prima.

Comprendere le Funzioni Generator

Le Basi delle Funzioni Generator

Una funzione generator si dichiara come una funzione normale ma con un asterisco dopo la parola chiave function: function*. L'asterisco è ciò che contrassegna la funzione come generator.

Chiamare una funzione generator non esegue il suo corpo. Restituisce invece un oggetto generator — un iterator che puoi guidare manualmente. Ogni chiamata al suo metodo next() esegue il corpo fino al prossimo yield, poi si mette in pausa e restituisce { value, done }:

javascript— editable

Il primo next() viene eseguito fino al primo yield 'Hello' e si mette in pausa lì. Il secondo riprende dopo quella riga ed esegue fino a yield 'World'. Il terzo riprende, non trova altri yield, raggiunge la fine della funzione e riporta done: true. Chiamare next() ulteriormente continuerà a restituire { value: undefined, done: true }.

Poiché un oggetto generator è anche iterabile, puoi consumarlo con for...of, l'operatore spread, o la destrutturazione — tutti si fermano automaticamente quando done diventa true:

javascript— editable
Nota

Un oggetto generator può essere iterato una sola volta. Una volta esaurito, for...of non produce nulla. Chiama di nuovo la funzione generator per ottenere un generator nuovo.

Il valore return di un generator

Un return all'interno di un generator termina l'iterazione e fornisce il valore finale insieme a done: true. Nota che for...of ignora questo valore restituito — vede solo quelli ceduti con yield:

javascript— editable

Controllare il Flusso con return() e throw()

Oltre a next(), un oggetto generator espone altri due metodi che permettono al chiamante di guidare l'esecuzione dall'esterno:

  • generator.return(value) forza il generator a terminare immediatamente, eseguendo eventuali blocchi finally lungo il percorso e restituendo { value, done: true }.
  • generator.throw(error) inietta un'eccezione nel punto yield corrente, così il generator può catturarla con try...catch — oppure propagarla se non lo fa.
javascript— editable

Il blocco finally rende i generator un posto ordinato per rilasciare risorse (chiudere un file, disconnettere uno stream) anche quando l'iterazione viene abbandonata prematuramente.

Pattern Avanzati con i Generator

Delegare con yield*

Quando un generator deve produrre i valori di un altro generator o di qualsiasi iterabile, usa yield* (leggi "yield-delegate") invece di scrivere un ciclo manuale. Inoltra in modo trasparente ogni valore dalla sorgente delegata:

javascript— editable

Un dettaglio utile: il valore dell'espressione di yield* è il valore return del generator interno, il che ti permette di comporre generator e passare un risultato al generator esterno:

javascript— editable

Inviare Valori ai Generator

La comunicazione con un generator è bidirezionale. Un'espressione yield non solo invia un valore verso l'esterno attraverso next(), ma valuta anche ciò che passi verso l'interno nella chiamata successiva next(value). Questo trasforma un generator in una piccola coroutine interattiva:

javascript— editable

Il primo next() viene eseguito fino al primo yield e restituisce la domanda; il suo argomento viene scartato perché non c'è ancora nessun yield in pausa che possa riceverlo. Il secondo next('Alice') riprende il yield in pausa, quindi l'espressione diventa 'Alice' e viene assegnata a name.

Applicazioni Pratiche dei Generator JavaScript

Costruire Iterabili Personalizzati

L'uso più comune dei generator nel mondo reale è rendere iterabili i propri oggetti. Definisci [Symbol.iterator] come metodo generator, e qualsiasi for...of, spread o destrutturazione funzionerà sull'oggetto. Questo richiede molto meno codice boilerplate rispetto alla scrittura di un oggetto iterator con un next() scritto a mano (vedi tipo Symbol per cosa è Symbol.iterator):

javascript— editable

Sequenze Lazy e Infinite

Poiché un generator calcola ogni valore solo quando viene richiesto, può descrivere una sequenza concettualmente infinita senza mai esaurire la memoria. L'esempio classico è un contatore, ma lo stesso approccio costruisce intervalli, generator di ID, o stream di Fibonacci. Lo si combina con un helper "take" che si ferma dopo il numero di elementi necessari:

javascript— editable

Un generator di intervallo parametrizzato è una variante comoda e riutilizzabile della stessa idea:

javascript— editable

Gestire le Operazioni Asincrone

Storicamente, i generator venivano usati per appiattire il "callback hell": ogni yield si metteva in pausa su una Promise, e un runner esterno riprendeva il generator una volta che la Promise si risolveva. L'esempio seguente mostra la meccanica manuale in modo da capire cosa succede sotto il cofano:

javascript— editable
Nota

Questo è un runner manuale semplificato. Nel codice moderno scriveresti questo con async/await, che il linguaggio ha costruito direttamente sopra questo pattern di generator-più-Promise. Per l'iterazione asincrona (trasmissione di blocchi nel tempo) usa i generator asincroni con async function* e for await...of.

Generator vs. Funzioni Normali

AspettoFunzione normaleFunzione generator
Dichiarazionefunction fn()function* fn()
Chiamarlaesegue il corpo fino al completamentorestituisce un oggetto generator, non esegue ancora nulla
Restituisceun singolo valoreuno stream di valori tramite yield
Può mettersi in pausa?nosì, ad ogni yield
Iterabile?nosì (funziona con for...of, spread)

Usa un generator quando hai bisogno di valori prodotti in modo lazy o su richiesta, di un oggetto che sia iterabile, o di una sequenza che potrebbe essere infinita. Per una semplice computazione una-tantum, una funzione normale è più semplice e veloce.

Conclusione

I generator offrono a JavaScript un modo pulito per produrre sequenze in modo lazy, mettere in pausa e riprendere la logica, e far funzionare qualsiasi oggetto con i cicli come for...of. Padroneggia yield per emettere valori, yield* per delegare ad altri iterabili, e next()/return()/throw() per guidare e controllare il flusso — e avrai uno strumento che alimenta tutto, dagli iterabili personalizzati alla sintassi async/await costruita sopra di esso.

Esercizio

Pratica
Qual è la funzione del carattere '*' prima della parola chiave function nei generator JavaScript?
Qual è la funzione del carattere '*' prima della parola chiave function nei generator JavaScript?
Was this page helpful?