Introduction

Ce cours aborde les concepts avancés de la programmation asynchrone en JavaScript, y compris les promesses, async/await, la gestion des erreurs, et les patterns de conception asynchrones. Chaque sous-chapitre comprend des exemples pratiques pour illustrer les concepts.


1. Promesses et Async/Await

Promesses

Les promesses en JavaScript permettent de gérer des opérations asynchrones. Elles retournent un objet représentant une valeur qui peut être disponible maintenant, dans le futur, ou jamais.

Exemple :

L'exemple donné illustre comment créer et utiliser une promesse en JavaScript pour simuler le chargement de données. Voici une explication détaillée de cet exemple :

function fetchData() {
  return new Promise((resolve, reject) => {
    // Simule un appel réseau avec un délai de 2 secondes
    setTimeout(() => resolve("Données chargées"), 2000);
  });
}

fetchData().then(data => console.log(data));

Détails :

  • Création d'une Promesse : La fonction fetchData() renvoie une nouvelle promesse. La promesse prend en argument une fonction exécuteur avec deux paramètres : resolve et reject.
  • setTimeout : À l'intérieur de la promesse, setTimeout est utilisé pour simuler un délai réseau, représenté ici par 2000 millisecondes (2 secondes). Après ce délai, la promesse est résolue avec le texte "Données chargées".
  • Résolution de la Promesse : Lorsque la promesse est résolue, la chaîne "Données chargées" est passée en tant que résultat à la fonction de rappel .then(), qui affiche ces données dans la console.

Utilisation Pratique

Cet exemple est utile pour comprendre comment les promesses permettent de gérer des opérations asynchrones en JavaScript, telles que les appels réseau, de manière propre et efficace. L'utilisation de resolve dans une promesse permet de signaler que l'opération asynchrone est terminée et de transmettre le résultat à la méthode .then(), qui peut ensuite traiter ce résultat.

 

Async/Await

Async/await simplifie la syntaxe de travail avec des promesses, permettant un code asynchrone qui ressemble à un code synchrone traditionnel.

Exemple :

L'exemple donné illustre l'utilisation de la syntaxe async/await pour effectuer des opérations asynchrones en JavaScript, en particulier pour charger des données de manière asynchrone et les traiter. Voici une explication détaillée de cet exemple :

async function loadAndProcessData() {
  try {
    // Tentative d'exécution du code susceptible de générer une erreur
    const data = await fetchData(); // Attente de la résolution de la promesse retournée par fetchData()
    console.log(data); // Si fetchData() réussit, affiche les données
  } catch (error) {
    // Bloc catch pour gérer les erreurs si fetchData() échoue
    console.error("Erreur lors du chargement des données", error);
  }
}

Détails :

  • async : Le mot-clé async avant la déclaration de fonction indique que la fonction est asynchrone et peut contenir des expressions await pour attendre des promesses.
  • await : Le mot-clé await est utilisé pour attendre que la promesse retournée par fetchData() se résolve ou se rejette. Cela suspend l'exécution de la fonction asynchrone, permettant au code de s'exécuter comme si c'était une opération synchrone.
  • Bloc try...catch : Utilisé ici pour gérer les erreurs de manière élégante. Le try exécute le code qui pourrait échouer (ici, le chargement des données). Si une erreur survient pendant l'attente de la promesse, elle est captée par le catch, où elle peut être traitée ou enregistrée.

Utilisation Pratique

Cet exemple est particulièrement utile dans des situations où des données doivent être chargées depuis une source externe (comme une API web) et où les erreurs de réseau ou de parsing sont possibles. L'utilisation de async/await rend le code plus lisible et plus facile à maintenir comparé à l'enchaînement de promesses avec .then() et .catch().


2. Gestion des Erreurs

La gestion des erreurs dans les opérations asynchrones est cruciale pour maintenir la stabilité de l'application.

Exemple avec Promesses :

L'exemple donné illustre comment utiliser les méthodes .then() et .catch() pour gérer les résultats et les erreurs potentielles d'une promesse en JavaScript. Voici une explication détaillée :

fetchData().then(data => {
  console.log(data);
}).catch(error => {
  console.error("Erreur détectée", error);
});

Détails :

  • fetchData() : Appel à une fonction qui retourne une promesse. Cette promesse pourrait être résolue avec des données ou rejetée avec une erreur.
  • .then(data => ...) : La méthode .then() est utilisée pour traiter le résultat de la promesse une fois qu'elle est résolue. Ici, si fetchData() se résout avec succès, les données reçues ("Données chargées") sont affichées dans la console.
  • .catch(error => ...) : La méthode .catch() est utilisée pour attraper et gérer les erreurs si la promesse est rejetée. Par exemple, si fetchData() échoue pour une raison quelconque, l'erreur est capturée ici et un message d'erreur est affiché dans la console.

Utilisation Pratique

Cet exemple montre la structure de base pour gérer les opérations asynchrones en JavaScript de manière sûre. En séparant le traitement des résultats et des erreurs, le code reste propre et facile à comprendre, tout en évitant les interruptions dues à des erreurs inattendues dans les opérations asynchrones. Cela garantit que les erreurs sont traitées de manière appropriée et que le programme peut continuer à fonctionner ou se terminer gracieusement.

Exemple avec Async/Await :

L'exemple donné illustre l'utilisation de la syntaxe async/await pour gérer les opérations asynchrones dans une fonction, tout en intégrant un bloc try...catch pour la gestion des erreurs.

async function safeDataHandling() {
  try {
    const data = await fetchData(); // Tente d'exécuter fetchData qui retourne une promesse
    console.log(data); // Si la promesse est résolue, affiche les données
  } catch (error) {
    // Si une erreur se produit pendant l'exécution de fetchData
    console.error("Erreur capturée", error); // Affiche l'erreur dans la console
  }
}

Détails :

  • async: Déclare que safeDataHandling est une fonction asynchrone, permettant l'utilisation de await à l'intérieur.
  • await fetchData(): Attend que la promesse retournée par fetchData() se résolve ou se rejette. Suspend l'exécution de la fonction jusqu'à ce que la promesse se termine.
  • Bloc try...catch : Capture les erreurs potentielles qui peuvent survenir pendant l'attente de la promesse. Ceci est essentiel pour éviter que les erreurs ne se propagent et interrompent le flux d'exécution du programme.

Utilisation Pratique

Cet exemple est pratique pour les développeurs qui doivent charger des données de manière fiable, traiter les résultats, et gérer les erreurs sans interrompre le fonctionnement de leur application. Utiliser async/await avec un bloc try...catch permet un contrôle précis sur le flux d'exécution et la gestion des erreurs dans des contextes asynchrones.


3. Patterns de Conception Asynchrones

Pattern de Publication/Souscription (Pub/Sub)

Ce pattern permet de créer des systèmes décentralisés où les émetteurs d'événements n'ont pas besoin de connaître les consommateurs de ces événements.

Exemple :

L'exemple donné illustre l'utilisation du module events de Node.js pour gérer les événements personnalisés avec un EventEmitter.

const EventEmitter = require('events');
const emitter = new EventEmitter();

// Abonnement à un événement
emitter.on('dataReceived', data => {
  console.log('Données reçues:', data);
});

// Émission de l'événement
emitter.emit('dataReceived', 'Quelques données');

Détails :

  • Création de l'EventEmitter : Un objet emitter est créé en instanciant EventEmitter, qui permet d'écouter et d'émettre des événements.
  • Abonnement à l'événement : La méthode .on() est utilisée pour écouter l'événement nommé dataReceived. Lorsque cet événement est émis, la fonction de rappel associée est appelée et affiche les données reçues.
  • Émission de l'événement : La méthode .emit() est utilisée pour déclencher l'événement dataReceived, passant 'Quelques données' comme argument à la fonction de rappel.

Utilisation Pratique

Cet exemple montre comment implémenter un système simple de publication/souscription en Node.js, où un émetteur peut notifier les abonnés d'un événement spécifique, rendant le code modulaire et facile à maintenir. C'est utile pour les architectures orientées événement où différents composants doivent communiquer efficacement sans être fortement couplés.

Pattern de File d'Attente de Promesses

Utilisez des promesses pour gérer une file d'attente de tâches asynchrones.

Exemple :

L'exemple donné montre comment gérer une file d'attente de promesses en JavaScript pour exécuter des tâches asynchrones séquentiellement.

const queue = [];

function processQueue() {
  if (queue.length > 0) {
    const promise = queue.shift();
    promise.then(result => {
      console.log('Tâche traitée:', result);
      processQueue(); // Appelle récursivement processQueue pour traiter la prochaine promesse
    });
  }
}

// Ajouter des promesses à la file
queue.push(fetchData());
queue.push(fetchData());

// Démarrer le traitement
processQueue();

Détails :

  • File d'attente (queue) : Un tableau qui stocke les promesses en attente d'exécution.
  • Traitement de la file (processQueue) : Une fonction qui gère la file d'attente. Elle retire la première promesse de la file, attend sa résolution, et affiche le résultat. Après chaque promesse résolue, elle rappelle elle-même pour traiter la prochaine promesse dans la file.
  • Ajout à la file : Des promesses sont ajoutées à la file. Ici, fetchData() est une fonction qui retourne une promesse (supposée être définie ailleurs).
  • Démarrage du traitement : processQueue() est appelé pour commencer à traiter les éléments dans la file.

Utilisation Pratique

Ce modèle est particulièrement utile dans des scénarios où l'ordre d'exécution est crucial pour les tâches asynchrones. Il garantit que chaque tâche est traitée l'une après l'autre sans créer de congestion due à de nombreuses promesses s'exécutant en parallèle. C'est une technique efficace pour gérer les ressources et éviter les conflits dans des environnements asynchrones complexes.

Ces exemples fournissent une fondation solide pour comprendre et appliquer la programmation asynchrone dans vos projets JavaScript, en rendant vos applications plus efficaces et réactives.

Modifié le: jeudi 16 mai 2024, 09:51