W3docs

Fonctions génératrices JavaScript

Apprenez les générateurs JavaScript : syntaxe function*, yield et yield*, envoi de valeurs avec next(), return() et throw(), séquences infinies paresseuses.

Un générateur est un type de fonction spécial capable de se mettre en pause au milieu de son exécution, de renvoyer une valeur à l'appelant, puis de reprendre exactement là où il s'était arrêté la prochaine fois que vous en demandez davantage. Au lieu de tout calculer d'avance et de retourner une seule fois, un générateur produit une séquence de valeurs de manière paresseuse — une à la fois, uniquement à la demande.

Cette idée simple fait des générateurs la solution la plus élégante en JavaScript pour construire des itérables personnalisés, modéliser des séquences infinies sans épuiser la mémoire, et parcourir une logique longue sur demande. Ce guide couvre la syntaxe function*, yield et yield*, la communication bidirectionnelle avec next(), la terminaison anticipée, et les cas pratiques où les générateurs brillent.

Cette page s'appuie sur les itérables et itérateurs — si le protocole d'itérateur vous est inconnu, lisez-le d'abord.

Comprendre les fonctions génératrices

Les bases des fonctions génératrices

Une fonction génératrice se déclare comme une fonction classique, mais avec une étoile après le mot-clé function : function*. L'étoile est ce qui distingue la fonction comme générateur.

Appeler une fonction génératrice n'exécute pas son corps. Elle retourne à la place un objet générateur — un itérateur que vous pilotez manuellement. Chaque appel à sa méthode next() exécute le corps jusqu'au prochain yield, puis se met en pause et retourne { value, done } :

javascript— editable

Le premier next() s'exécute jusqu'au premier yield 'Hello' et s'y arrête. Le deuxième reprend après cette ligne et s'exécute jusqu'à yield 'World'. Le troisième reprend, ne trouve plus d'instruction yield, atteint la fin de la fonction et signale done: true. Appeler next() à nouveau continuerait de retourner { value: undefined, done: true }.

Parce qu'un objet générateur est également itérable, vous pouvez le consommer avec for...of, l'opérateur de décomposition, ou la déstructuration — qui s'arrêtent tous automatiquement quand done devient true :

javascript— editable
Note

Un objet générateur ne peut être itéré qu'une seule fois. Une fois épuisé, for...of ne produit rien. Appelez à nouveau la fonction génératrice pour obtenir un nouveau générateur.

La valeur de retour d'un générateur

Un return dans un générateur met fin à l'itération et fournit la valeur finale avec done: true. Notez que for...of ignore cette valeur retournée — il ne voit que les valeurs produites par yield :

javascript— editable

Contrôler le flux avec return() et throw()

En plus de next(), un objet générateur expose deux méthodes supplémentaires qui permettent à l'appelant de piloter l'exécution depuis l'extérieur :

  • generator.return(value) force le générateur à se terminer immédiatement, en exécutant tous les blocs finally au passage et en retournant { value, done: true }.
  • generator.throw(error) injecte une exception au niveau du yield courant, permettant au générateur de la capturer avec try...catch — ou de la propager s'il ne le fait pas.
javascript— editable

Le bloc finally fait des générateurs un endroit idéal pour libérer des ressources (fermer un fichier, déconnecter un flux) même lorsque l'itération est abandonnée prématurément.

Modèles avancés de générateurs

Déléguer avec yield*

Quand un générateur doit produire les valeurs d'un autre générateur ou d'un itérable quelconque, utilisez yield* (prononcé « yield-déléguer ») au lieu d'écrire une boucle manuelle. Il transfère de manière transparente chaque valeur de la source déléguée :

javascript— editable

Un détail utile : la valeur de l'expression yield* est la valeur de return du générateur interne, ce qui permet de composer des générateurs et de renvoyer un résultat au générateur externe :

javascript— editable

Envoyer des valeurs dans les générateurs

La communication avec un générateur est bidirectionnelle. Une expression yield envoie non seulement une valeur vers l'extérieur via next(), elle prend aussi pour valeur ce que vous passez dans le prochain appel next(value). Cela transforme un générateur en une petite coroutine interactive :

javascript— editable

Le premier next() s'exécute jusqu'au premier yield et retourne la question ; son argument est ignoré car il n'y a pas de yield en pause pour le recevoir. Le deuxième next('Alice') reprend le yield en pause, l'expression devient donc 'Alice' et est assignée à name.

Applications pratiques des générateurs JavaScript

Construire des itérables personnalisés

L'utilisation la plus courante des générateurs en pratique est de rendre vos propres objets itérables. Définissez [Symbol.iterator] comme méthode génératrice, et tout for...of, décomposition ou déstructuration fonctionnera sur l'object. C'est bien moins verbeux qu'écrire un objet itérateur avec un next() fait à la main (voir le type Symbol pour savoir ce qu'est Symbol.iterator) :

javascript— editable

Séquences paresseuses et infinies

Parce qu'un générateur calcule chaque valeur uniquement à la demande, il peut décrire une séquence conceptuellement infinie sans jamais épuiser la mémoire. L'exemple classique est un compteur, mais la même approche permet de construire des plages, des générateurs d'identifiants, ou des flux de Fibonacci. On le combine avec un assistant « take » qui s'arrête après le nombre de valeurs souhaité :

javascript— editable

Un générateur de plage paramétré est une variante pratique et réutilisable de la même idée :

javascript— editable

Gérer les opérations asynchrones

Historiquement, les générateurs étaient utilisés pour aplatir le « callback hell » : chaque yield se mettait en pause sur une Promise, et un exécuteur externe reprenait le générateur une fois cette Promise résolue. L'exemple ci-dessous montre la mécanique manuelle pour que vous compreniez ce qui se passe sous le capot :

javascript— editable
Note

Il s'agit d'un exécuteur manuel simplifié. Dans du code moderne, vous écririez cela avec async/await, que le langage a construit directement sur ce modèle générateur + Promise. Pour l'itération asynchrone (chunks en streaming dans le temps), utilisez les générateurs asynchrones avec async function* et for await...of.

Générateurs vs. fonctions classiques

AspectFonction classiqueFonction génératrice
Déclarationfunction fn()function* fn()
Appelexécute le corps jusqu'à la finretourne un objet générateur, n'exécute rien encore
Retourneune valeur uniqueun flux de valeurs via yield
Peut se mettre en pause ?nonoui, à chaque yield
Itérable ?nonoui (fonctionne avec for...of, décomposition)

Choisissez un générateur quand vous avez besoin de valeurs produites paresseusement ou à la demande, d'un objet itérable, ou d'une séquence potentiellement infinie. Pour un calcul simple et unique, une fonction classique est plus simple et plus rapide.

Conclusion

Les générateurs offrent à JavaScript une façon élégante de produire des séquences paresseusement, de mettre en pause et reprendre une logique, et de faire fonctionner n'importe quel objet avec des boucles comme for...of. Maîtrisez yield pour émettre des valeurs, yield* pour déléguer à d'autres itérables, et next()/return()/throw() pour piloter et contrôler le flux — et vous disposerez d'un outil qui alimente tout, des itérables personnalisés à la syntaxe async/await construite par-dessus.

Pratique

Pratique
Quel est le rôle du caractère '*' avant le mot-clé function dans les générateurs JavaScript ?
Quel est le rôle du caractère '*' avant le mot-clé function dans les générateurs JavaScript ?
Was this page helpful?