Fonctions génératrices en JavaScript
Dans cet article, nous expliquerons les fonctions génératrices en JavaScript.
YouTube Video
Fonctions génératrices en JavaScript
Les fonctions génératrices en JavaScript sont des fonctions spéciales qui diffèrent des fonctions ordinaires, car elles peuvent effectuer une exécution paresseuse et mettre en pause et reprendre. En comprenant les fonctions génératrices, vous pouvez gérer efficacement les opérations asynchrones et le traitement séquentiel de grandes quantités de données. Ici, nous fournirons une explication détaillée du fonctionnement des fonctions génératrices, de leur utilisation et des cas d'utilisation pratiques.
Qu'est-ce qu'une fonction génératrice ?
Une fonction génératrice est définie avec function*
(une définition de fonction avec un astérisque) et, contrairement aux fonctions normales, elle peut mettre en pause l'exécution à mi-parcours et la reprendre tout en maintenant son état. Les fonctions génératrices permettent une "exécution paresseuse" et retournent les résultats progressivement, permettant une gestion efficace de la mémoire et un traitement séquentiel.
Syntaxe
1function* generatorFunction() {
2 yield 'First value';
3 yield 'Second value';
4 return 'Done';
5}
De cette manière, une fonction génératrice peut contenir plusieurs expressions yield
et utiliser yield
pour suspendre son exécution. Lorsqu'une fonction génératrice est appelée, le corps de la fonction n'est pas exécuté immédiatement, et un objet générateur est retourné. Vous pouvez appeler la méthode next()
sur cet objet pour reprendre la fonction à partir de l'endroit où elle a été mise en pause.
Utilisation de base des fonctions génératrices
Ensuite, examinons un exemple basique d'utilisation des fonctions génératrices.
1function* simpleGenerator() {
2 yield 1;
3 yield 2;
4 yield 3;
5}
6
7const gen = simpleGenerator();
8
9console.log(gen.next()); // { value: 1, done: false }
10console.log(gen.next()); // { value: 2, done: false }
11console.log(gen.next()); // { value: 3, done: false }
12console.log(gen.next()); // { value: undefined, done: true }
Un point important à noter ici est que le générateur retourne des valeurs à chaque fois avec yield
, et tant que la propriété done
est false
, cela indique qu'il reste d'autres valeurs à venir. Le dernier appel à next()
retourne done: true
, ce qui indique que le générateur est terminé.
Le mot-clé yield
et la suspension des valeurs
yield
est un mot-clé qui indique un point de pause à l'intérieur d'une fonction génératrice. La valeur à droite de yield
est retournée lorsque next()
est appelé. De plus, yield
permet une communication bidirectionnelle. Autrement dit, lorsqu'une valeur est passée comme argument à la méthode next()
, cette valeur est envoyée à la fonction génératrice.
1function* generatorWithYield() {
2 const value1 = yield 'First yield';
3 console.log('Received value:', value1);
4 const value2 = yield 'Second yield';
5 console.log('Received value:', value2);
6}
7
8const gen = generatorWithYield();
9
10console.log(gen.next()); // { value: 'First yield', done: false }
11console.log(gen.next('Apple')); // Received value: Apple
12 // { value: 'Second yield', done: false }
13console.log(gen.next('Banana'));// Received value: Banana
14 // { value: undefined, done: true }
Dans cet exemple, l'appel next('Apple')
envoie la valeur 'Apple'
à la fonction génératrice, où elle est utilisée à l'intérieur de la fonction.
Gestion de l'état du générateur
Les générateurs peuvent maintenir leur état d'exécution, ce qui permet une représentation concise des boucles longues ou du traitement séquentiel. L'exemple suivant démontre un générateur qui produit des nombres indéfiniment.
1function* infiniteGenerator() {
2 let i = 0;
3 while (true) {
4 yield i++;
5 if (i > 10) {
6 break;
7 }
8 }
9}
10
11const gen = infiniteGenerator();
12
13console.log(gen.next().value); // 0
14console.log(gen.next().value); // 1
15console.log(gen.next().value); // 2
16// Continues...
Ce générateur produit continuellement des nombres en utilisant une boucle while(true)
, vous permettant d'obtenir des valeurs selon vos besoins. Cela permet un traitement efficace de grands ensembles de données.
Applications des fonctions génératrices
Les fonctions génératrices conviennent à l'exécution séquentielle de plusieurs processus. Par exemple, elles sont utiles pour traiter des requêtes API de manière séquentielle ou pour diviser et traiter de grands fichiers.
1function* apiRequestGenerator() {
2 yield fetch('https://codesparklab.com/json/example1.json');
3 yield fetch('https://codesparklab.com/json/example2.json');
4 yield fetch('https://codesparklab.com/json/example3.json');
5}
Ainsi, les générateurs, qui peuvent être utilisés pour le traitement asynchrone, sont extrêmement bénéfiques pour une gestion efficace des données séquentielles.
Générateurs asynchrones
Les générateurs asynchrones, introduits dans ES2018, permettent de renvoyer des valeurs asynchrones de manière séquentielle en combinant async
et yield
. Cela permet d'écrire de manière concise des traitements asynchrones en combinaison avec await
.
Syntaxe
1async function* asyncGenerator() {
2 yield await Promise.resolve(1);
3 yield await Promise.resolve(2);
4 yield await Promise.resolve(3);
5}
6
7const gen = asyncGenerator();
8
9(async () => {
10 for await (const value of gen) {
11 console.log(value); // 1, 2, 3
12 }
13})();
Les générateurs asynchrones peuvent récupérer des valeurs de manière séquentielle en utilisant une boucle for await...of
. Ce modèle est particulièrement utile lors du traitement de flux de données asynchrones.
Exemple pratique : Simplifier le traitement asynchrone avec des générateurs
Les fonctions génératrices sont également utilisées pour simplifier le flux du traitement asynchrone. Par exemple, en combinant yield
et Promise
comme illustré ci-dessous, vous pouvez écrire des opérations asynchrones pour qu'elles paraissent synchrones.
1function* asyncFlow() {
2 const data1 = yield fetch('https://codesparklab.com/json/example1.json');
3 console.log(data1);
4 const data2 = yield fetch('https://codesparklab.com/json/example2.json');
5 console.log(data2);
6}
7
8const gen = asyncFlow();
9
10function handleAsync(generator) {
11 const next = (promise) => {
12 promise.then((result) => {
13 const { value, done } = generator.next(result);
14 if (!done) {
15 next(value);
16 }
17 });
18 };
19
20 next(generator.next().value);
21}
22
23handleAsync(gen);
Ce code effectue séquentiellement des requêtes API à l'aide d'un générateur et traite les résultats.
Résumé
Les fonctions génératrices sont l'une des fonctionnalités puissantes de JavaScript, possédant la capacité de mettre en pause et de reprendre l'exécution d'une fonction. Cela permet un traitement séquentiel, un traitement asynchrone et une manipulation efficace de grands ensembles de données. Comprendre les générateurs est une étape importante pour maîtriser les techniques avancées en JavaScript.
Vous pouvez suivre l'article ci-dessus avec Visual Studio Code sur notre chaîne YouTube. Veuillez également consulter la chaîne YouTube.