Programmation asynchrone Node.js

Dans la programmationsynchrone traditionnelle, le code est exécuté séquentiellement, et chaque ligne de code doit attendre que la ligne précédente ait fini de s'exécuter avant de pouvoir s'exécuter. Cependant,la programmation asynchronepermet au code de continuer à exécuter d'autres tâches en attendant que certaines opérations (telles que les opérations d'E/S) soient terminées, sans bloquer l'exécution du programme.

Node.js adopte un modèle d'E/S asynchrone, ce qui le rend particulièrement adapté à la gestion d'applications réseau à haute concurrence. Comprendre la programmation asynchrone est essentiel pour maîtriser Node.js.


Pourquoi Node.js a besoin de la programmation asynchrone

Node.js est mono-thread, ce qui signifie qu'il ne peut exécuter qu'une seule tâche à la fois. Si la programmation synchrone est utilisée, lorsqu'une opération chronophage (comme la lecture d'un fichier volumineux ou une requête réseau) est exécutée, le programme entier sera bloqué et incapable de traiter d'autres requêtes.

La programmation asynchrone résout ce problème:

  • Améliore le débit des applications
  • Utilise plus efficacement les ressources système
  • Offre une meilleure expérience utilisateur

Trois manières principales de programmation asynchrone dans Node.js

1. Fonctions de rappel (Callbacks)

Les fonctions de rappel sont la méthode de gestion asynchrone la plus élémentaire dans Node.js. Elles fonctionnent en passant une fonction comme argument à une autre fonction, et cette fonction est appelée une fois l'opération terminée.

Exemple

const fs = require('fs');

// Lire le fichier de manière asynchrone
fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Erreur de lecture du fichier :', err);
    return;
  }
  console.log('Contenu du fichier:', data);
});

console.log('Demande de lecture du fichier envoyée, poursuite de l'exécution d'un autre code...');

Fonctionnalités:

  • Simple et direct
  • Mène facilement à l'"enfer des callbacks"
  • La gestion des erreurs n'est pas assez intuitive

2、Promise

Promise est une solution de programmation asynchrone introduite dans ES6. Elle représente l'achèvement ou l'échec éventuel d'une opération asynchrone et sa valeur résultante.

Exemple

const fs = require('fs').promises;

// Lire un fichier à l'aide de Promise
fs.readFile('example.txt', 'utf8')
  .then(data => {
    console.log('Contenu du fichier:', data);
  })
  .catch(err => {
    console.error('Erreur de lecture du fichier :', err);
  });

console.log('Demande de lecture du fichier envoyée, poursuite de l'exécution d'un autre code...');

Fonctionnalités:

  • Appels chaînés, évitant l'enfer des callbacks
  • Meilleur mécanisme de gestion des erreurs
  • L'état est irréversible (pending → fulfilled ou rejected)

3、async/await

async/await est du sucre syntaxique introduit dans ES8, basé sur Promise, faisant ressembler le code asynchrone à du code synchrone.

Exemple

const fs = require('fs').promises;

async function readFile() {
  try {
    const data = await fs.readFile('example.txt', 'utf8');
    console.log('Contenu du fichier:', data);
  } catch (err) {
    console.error('Erreur de lecture du fichier :', err);
  }
}

readFile();
console.log('Demande de lecture du fichier envoyée, poursuite de l'exécution d'un autre code...');

Fonctionnalités:

  • Le code est plus concis et lisible
  • La gestion des erreurs utilise une structure try/catch
  • Doit être utilisé dans des fonctions async

Bonnes pratiques de gestion des erreurs

Gestion des erreurs dans les fonctions de rappel

Exemple

fs.readFile('example.txt', 'utf8', (err, data) => {
  if (err) {
    console.error('Erreur de lecture du fichier :', err);
    return; // Important : return après la gestion de l'erreur pour éviter d'exécuter le code suivant
  }
  console.log('Contenu du fichier:', data);
});

Gestion des erreurs de Promise

Exemple

fs.readFile('example.txt', 'utf8')
  .then(data => {
    console.log('Contenu du fichier:', data);
    return someOtherAsyncOperation(data);
  })
  .then(result => {
    console.log('Résultat de la deuxième étape :', result);
  })
  .catch(err => {
    console.error('Erreur lors du traitement :', err);
  });

Gestion des erreurs avec async/await

Exemple

async function processData() {
  try {
    const data = await fs.readFile('example.txt', 'utf8');
    const result = await someOtherAsyncOperation(data);
    console.log('Résultat final :', result);
  } catch (err) {
    console.error('Erreur lors du traitement :', err);
  }
}

processData();

Considérations de performance

  1. Évitez de bloquer la boucle d'événements: le code synchrone de longue durée bloquera toute l'application
  2. Utilisez les opérations asynchrones à bon escient: Toutes les opérations n'ont pas besoin d'être asynchrones ; les tâches de calcul simples peuvent être plus efficaces avec des méthodes synchrones
  3. Contrôlez le degré de concurrence: Trop d'opérations asynchrones parallèles peuvent entraîner un épuisement des ressources
  4. Utilisez des flux pour traiter les fichiers volumineux: Pour les fichiers volumineux, utilisez des flux au lieu de les lire entièrement en une seule fois
Autres extensions