Maison >interface Web >js tutoriel >Générateurs JavaScript : boostez votre code avec la puissance de pause !
Les générateurs JavaScript sont plutôt sympas. Ce sont des fonctions normales, mais avec des super pouvoirs. Je les ai beaucoup utilisés ces derniers temps, et je dois dire qu'ils ont changé ma façon de penser le flux de contrôle dans mon code.
Commençons par les bases. Un générateur est une fonction qui peut être mise en pause et reprise. Il utilise la syntaxe function* et le mot-clé rendement. Voici un exemple simple :
function* countToThree() { yield 1; yield 2; yield 3; } const counter = countToThree(); console.log(counter.next().value); // 1 console.log(counter.next().value); // 2 console.log(counter.next().value); // 3
Vous voyez comment nous pouvons parcourir la fonction un rendement à la fois ? C'est la magie des générateurs.
Mais les générateurs peuvent faire bien plus que simplement compter. Ils sont parfaits pour créer des itérateurs personnalisés. Supposons que vous souhaitiez générer une séquence de Fibonacci :
function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { yield curr; [prev, curr] = [curr, prev + curr]; } } const fib = fibonacci(); for (let i = 0; i < 10; i++) { console.log(fib.next().value); }
Ce générateur continuera à produire des nombres de Fibonacci pour toujours. C'est une séquence infinie, mais nous calculons uniquement les valeurs dont nous avons besoin.
Cela nous amène à l'une des choses les plus intéressantes à propos des générateurs : l'évaluation paresseuse. Ils ne calculent les valeurs que lorsque nous les demandons. Cela peut être très efficace pour les grands ensembles de données ou les calculs complexes.
Regardons un exemple plus pratique. Supposons que vous construisiez un système de pagination pour un grand ensemble de données :
function* paginate(items, pageSize) { for (let i = 0; i < items.length; i += pageSize) { yield items.slice(i, i + pageSize); } } const allItems = Array.from({ length: 100 }, (_, i) => i + 1); const pageSize = 10; const pages = paginate(allItems, pageSize); console.log(pages.next().value); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(pages.next().value); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Ce générateur nous permet de récupérer des pages de données selon nos besoins, sans avoir à tout charger en mémoire en même temps.
Les générateurs brillent également en matière de programmation asynchrone. Ils peuvent donner au code asynchrone l’apparence et le comportement d’un code synchrone. Voici un exemple utilisant la bibliothèque co :
const co = require('co'); function* fetchUserData() { const user = yield fetchUser(); const posts = yield fetchPosts(user.id); const comments = yield fetchComments(posts[0].id); return { user, posts, comments }; } co(fetchUserData).then(result => { console.log(result); }).catch(error => { console.error(error); });
Ce code semble synchrone, mais il effectue en réalité trois appels asynchrones. Le générateur s'arrête à chaque rendement jusqu'à ce que la promesse soit résolue.
Les générateurs peuvent également être utilisés pour le multitâche coopératif. Vous pouvez créer plusieurs générateurs et basculer entre eux, simulant une exécution simultanée :
function* task1() { yield 'Start task 1'; yield 'Middle of task 1'; yield 'End task 1'; } function* task2() { yield 'Start task 2'; yield 'Middle of task 2'; yield 'End task 2'; } function run(tasks) { const iterations = tasks.map(task => task()); while (iterations.length) { const [first, ...rest] = iterations; const { value, done } = first.next(); if (!done) { console.log(value); iterations.push(first); } iterations.unshift(...rest); } } run([task1, task2]);
Ce code alterne entre les deux tâches, exécutant chacune une étape à la fois.
Les générateurs sont également parfaits pour créer des machines à états. Chaque rendement peut représenter un état différent :
function* trafficLight() { while (true) { yield 'red'; yield 'green'; yield 'yellow'; } } const light = trafficLight(); console.log(light.next().value); // red console.log(light.next().value); // green console.log(light.next().value); // yellow console.log(light.next().value); // red
Ce feu de circulation continuera à parcourir ses états indéfiniment.
Parlons maintenant de quelques techniques plus avancées. La délégation du générateur vous permet de céder le passage à un autre générateur :
function* innerGenerator() { yield 'inner 1'; yield 'inner 2'; } function* outerGenerator() { yield 'outer 1'; yield* innerGenerator(); yield 'outer 2'; } const gen = outerGenerator(); console.log(gen.next().value); // outer 1 console.log(gen.next().value); // inner 1 console.log(gen.next().value); // inner 2 console.log(gen.next().value); // outer 2
La syntaxe rendement* délègue à innerGenerator, renvoyant toutes ses valeurs avant de continuer avec externalGenerator.
La gestion des erreurs dans les générateurs mérite également d'être mentionnée. Vous pouvez lancer des erreurs dans un générateur en utilisant la méthode throw() :
function* errorGenerator() { try { yield 'Start'; yield 'Middle'; yield 'End'; } catch (error) { console.error('Caught:', error); yield 'Error handled'; } } const gen = errorGenerator(); console.log(gen.next().value); // Start console.log(gen.throw(new Error('Oops!')).value); // Caught: Error: Oops! // Error handled
Cela permet des stratégies de gestion des erreurs assez sophistiquées.
Les générateurs peuvent également être utilisés pour implémenter des algorithmes de backtracking. Voici un exemple simple qui génère toutes les combinaisons possibles d'éléments :
function* countToThree() { yield 1; yield 2; yield 3; } const counter = countToThree(); console.log(counter.next().value); // 1 console.log(counter.next().value); // 2 console.log(counter.next().value); // 3
Ce générateur produira toutes les combinaisons à 2 éléments des éléments donnés.
Un domaine dans lequel les générateurs brillent vraiment est le traitement de grandes quantités de données. Vous pouvez créer des pipelines de traitement de données efficaces qui calculent uniquement ce qui est nécessaire. Voici un exemple qui traite un gros fichier ligne par ligne :
function* fibonacci() { let [prev, curr] = [0, 1]; while (true) { yield curr; [prev, curr] = [curr, prev + curr]; } } const fib = fibonacci(); for (let i = 0; i < 10; i++) { console.log(fib.next().value); }
Ce générateur lit le fichier ligne par ligne, vous permettant de traiter des fichiers volumineux sans les charger entièrement en mémoire.
Les générateurs peuvent également être utilisés pour implémenter le modèle Observable. Voici une implémentation simple :
function* paginate(items, pageSize) { for (let i = 0; i < items.length; i += pageSize) { yield items.slice(i, i + pageSize); } } const allItems = Array.from({ length: 100 }, (_, i) => i + 1); const pageSize = 10; const pages = paginate(allItems, pageSize); console.log(pages.next().value); // [1, 2, 3, 4, 5, 6, 7, 8, 9, 10] console.log(pages.next().value); // [11, 12, 13, 14, 15, 16, 17, 18, 19, 20]
Ce générateur agit comme un observateur, traitant chaque donnée qu'il reçoit.
Une autre utilisation intéressante des générateurs consiste à créer des structures de contrôle personnalisées. Voici un exemple de fonction de nouvelle tentative qui utilise des générateurs :
const co = require('co'); function* fetchUserData() { const user = yield fetchUser(); const posts = yield fetchPosts(user.id); const comments = yield fetchComments(posts[0].id); return { user, posts, comments }; } co(fetchUserData).then(result => { console.log(result); }).catch(error => { console.error(error); });
Cette fonction de nouvelle tentative tentera la fonction donnée jusqu'à maxAttempts fois avant d'abandonner.
En conclusion, les générateurs sont une fonctionnalité puissante de JavaScript qui peut vous aider à écrire du code plus expressif, efficace et maintenable. Ils sont parfaits pour gérer des flux de contrôle complexes, gérer des opérations asynchrones et traiter de grands ensembles de données. Bien qu'ils puissent sembler un peu étranges au début, une fois que vous les maîtriserez, vous découvrirez toutes sortes de façons créatives de les utiliser dans vos projets. Alors n'hésitez plus, essayez les générateurs dans votre prochain projet JavaScript. Vous pourriez être surpris de voir à quel point ils peuvent simplifier votre code !
N'oubliez pas de consulter nos créations :
Centre des investisseurs | Vie intelligente | Époques & Échos | Mystères déroutants | Hindutva | Développeur Élite | Écoles JS
Tech Koala Insights | Epoques & Echos Monde | Support Central des Investisseurs | Mystères déroutants Medium | Sciences & Epoques Medium | Hindutva moderne
Ce qui précède est le contenu détaillé de. pour plus d'informations, suivez d'autres articles connexes sur le site Web de PHP en chinois!