Comment écrire du code asynchrone en Node.js

Comprendre la nature asynchrone fondamentale de Node.js. Une traduction de l'article How to write asynchronous code

Classée dans Pour commencer > Structure de contrôle

Traduction

Node.js encourage un style de codage asynchrone dès le départ, contrairement à la plupart des cadriciels (frameworks) web les plus populaires. Il y a un certain nombre de choses importantes dont il faut être conscient lorsqu'on apprend à écrire du code asynchrone - sinon, vous trouverez souvent votre code s'exécutant de manière extrêmement inattendue. Prenez cette règle (générale) à cœur :

Utilisez les fonctions asynchrones, évitez les fonctions synchrones !

De nombreuses fonctions du noyau de Node.js ont des versions synchrones et asynchrones. Dans la plupart des cas, il est préférable pour vous d'utiliser les fonctions asynchrones - sinon, pourquoi utiliser Node.js ?

Comme un exemple rapide comparant et contrastant les deux, en utilisant fs.readFile :

var fs = require('fs');

fs.readFile('example.file', 'utf8', function (err, data) {
  if (err) {
    return console.log(err);
  }
  console.log(data);
});

// ====================

var data = fs.readFileSync('example.file','utf8');
console.log(data);

En regardant simplement ces deux blocs de code, la version synchrone semble être plus concise. Cependant, la version asynchrone est plus compliquée pour une très bonne raison. Dans la version synchrone, le monde est mis en pause jusqu'à ce que la lecture du fichier soit terminée - votre processus restera là, à attendre le système d'exploitation (OS) (qui gère toutes les tâches du système de fichiers).

La version asynchrone, quant à elle, n'arrête pas le temps. Au lieu de cela, la fonction de rappel est appelée lorsque la lecture du fichier est terminée. Cela laisse votre processus libre d'exécuter d'autres codes pendant ce temps.

Lorsque vous ne lisez qu'un ou deux fichiers ou que vous enregistrez rapidement quelque chose, la différence entre les entrées/sorties ou E/S (I/O) de fichiers synchrones et asynchrones peut être assez faible. D'un autre côté, cependant, lorsque vous recevez plusieurs requêtes par seconde qui nécessitent des E/S de fichiers ou de bases de données, essayer d'effectuer ces E/S de manière synchrone serait tout à fait désastreux pour les performances.

Fonction de rappel

Les fonctions de rappel (callback functions) sont un idiome de base dans Node.js pour les opérations asynchrones. Quand la plupart des gens parlent de rappel, ils veulent dire la fonction qui est passée comme dernier paramètre à une fonction asynchrone. La fonction de rappel est ensuite appelé plus tard avec toute valeur de retour ou message d'erreur que la fonction a produit. Pour plus de détails, voir l'article sur les fonctions de rappel.

Emetteurs d'événements

Les émetteurs d'événements (Event Emitters) sont un autre idiome de base dans Node.js. Un constructeur est fourni dans le noyau de Node.js : require('events').EventEmitter. Un émetteur d'événements est généralement utilisé lorsque la réponse comporte plusieurs parties (puisque vous ne souhaitez généralement appeler un callback qu'une seule fois). Pour plus de détails, voir l'article sur les émetteurs d'événements.

Un problème avec le code asynchrone

Une erreur courante dans le code asynchrone avec JavaScript est d'écrire du code qui fait quelque chose comme ceci :

for (var i = 0; i < 5; i++) {
  setTimeout(function () {
    console.log(i);
  }, i);
}

La sortie inattendue est alors :

5
5
5
5
5

La raison pour laquelle cela se produit est que chaque délai est créé, puis i est incrémenté. Ensuite, lorsque le callback est appelé, il recherche la valeur de i et celle-ci est de 5. La solution consiste à créer une fermeture afin que la valeur actuelle de i soit stockée. Par exemple :

for (var i = 0; i < 5; i++) {
  (function(i) {
    setTimeout(function () {
      console.log(i);
    }, i);
  })(i);
}

Cela donne la bonne sortie :

0
1
2
3
4

Lire dans une autre langue