Générateurs : les bits gourmands en ressources

Le projet de spécification ECMAScript 6 a déjà séduit de nombreux développeurs JavaScript modernes. Nous avons abordé de nouvelles classes de collections et les boucles d'itération for..of dans un article précédent. Dans cet article, nous allons parler d'un élément qui va de pair avec les boucles for..of: les fonctions de générateur.

Il existe déjà de nombreux contenus de qualité qui expliquent pourquoi et comment utiliser les générateurs. En résumé, les générateurs sont des fonctions spéciales qui créent des itérateurs, et les itérateurs sont des objets dotés d'une méthode next(), qui peut être appelée pour obtenir une valeur. Dans une fonction de générateur, le mot clé yield fournit la valeur de next(). L'utilisation de yield suspend l'exécution de la fonction de générateur, en conservant l'état jusqu'à ce que next() soit rappelé, auquel cas le code recommence et continue, jusqu'à yield une autre valeur (ou jusqu'à la fin de la fonction de générateur). Il existe plusieurs cas d'utilisation canoniques des fonctions de générateur, comme leur utilisation pour itérer les nombres de la séquence de Fibonacci.

Maintenant que les principes de base sont terminés, examinons dans le détail un exemple de code JavaScript qui couvre certains des pièges, ou "bits complexes", liés à l'utilisation des générateurs. Elle contient de nombreux commentaires, et vous pouvez tester la version en ligne du code avant de le lire:

Quels sont les principaux points à retenir du code ?

Tout d'abord, la construction d'un générateur génère un itérateur unique doté de son propre état distinct, et vous pouvez transmettre des paramètres au constructeur du générateur qui peut contrôler le comportement.

Ensuite, vous pouvez transmettre un paramètre lorsque vous appelez la méthode next() d'un itérateur. Cette valeur sera attribuée à tout ce qui se trouve à gauche de l'instruction yield lors de l'appel de l'itérateur précédent. C'est un excellent moyen de faire varier la sortie de l'itérateur. Ici, nous l'utilisons pour contrôler si le mot renvoyé est en majuscules ou non. Si vous souhaitez influencer la toute première valeur renvoyée, utilisez un paramètre dans le constructeur du générateur.

Enfin, les générateurs peuvent produire des itérateurs finis ou infinis. Si vous travaillez avec un itérateur infini, assurez-vous d'avoir une condition de terminal basée sur la valeur yielded. Il est très facile d'écrire par erreur des boucles infinies, en particulier lorsque vous utilisez for..of pour des itérations. Si vous travaillez avec un itérateur fini via des appels à next(), la propriété .done de l'objet renvoyé indique si l'itération est terminée.

Nous espérons que cet exemple, ainsi que les autres ressources disponibles sur le Web, susciteront l'enthousiasme et vous inciteront à réfléchir à la façon dont vous pouvez utiliser les générateurs dans votre propre code. Les versions de Firefox (à partir de la version 31) et de Chrome (à partir de la version 39) sont compatibles avec les générateurs de manière native. Le projet Regenerator prend en charge d'autres navigateurs avec des générateurs, et vous pouvez également utiliser Traceur.

Merci à Erik Arvidsson pour son aide à la lecture de cet article.