I. Avant-propos

Les flux sont un des types de données les moins utilisés sous Node. Si vous êtes à l'aise avec Node, vous avez probablement entendu cela auparavant. Mais à force de voir plusieurs nouveaux modules de pop-up qui ne profitent pas des avantages des flux, ou, qui n'utilisent pas pleinement leur potentiel, je ressens le besoin de partager mes connaissances à ce sujet.

II. Modèle courant

Le modèle courant que je vois dans les modules nécessitant des flux en entrée est le suivant :

 
Sélectionnez
var foo = require('foo');

foo('/chemin/de/mon_fichier', function onResult(err, resultats) {
  // utilisation du résultat
});


En ayant uniquement un chemin d'accès à un fichier comme point d'entrée de votre module, vous limitez le flux que le module pourrait utiliser à un fichier accessible en lecture dont vous n'avez aucun contrôle.

III. Supporter d'autres flux

On pourrait croire qu'il est très fréquent pour un module de lire un fichier, mais cela ne tient pas compte du fait qu'un flux n'est pas seulement un fichier. Un flux peut être plusieurs choses. Il pourrait être un parseur, une requête HTTP ou un processus enfant. Il existe plusieurs autres possibilités.

Supporter uniquement des chemins d'accès à des fichiers limite les développeurs. Tout autre type de flux doit alors être écrit dans le système de fichiers et puis lu par après, ce qui est moins efficace. Une des raisons est la mémoire supplémentaire qui est nécessaire pour stocker le flux. Deuxièmement, il faut plus de temps pour diffuser le fichier sur le disque et ensuite pour lire les données dont l'utilisateur a besoin.

Pour éviter cela, l'API du module foo ci-dessus doit être écrite de cette façon :

 
Sélectionnez
var stream = fs.createReadStream('/chemin/de/mon_fichier');
foo(stream, function onResult(err, resultats) {
  // utilisation du résultat
});


Maintenant, l'exemple foo peut prendre n'importe quel type de flux en entrée, y compris un fichier. Cependant, passer un fichier est peut-être trop long. Le module fs est alors requis et un flux plus approprié doit être créé. La solution est de permettre de passer comme paramètre un flux ou bien un chemin d'accès à un fichier :

 
Sélectionnez
foo(streamOrPath, function onResult(err, resultats) {
  // ...
});


À l'intérieur de foo, on vérifie le type de streamOrPath et on crée un flux si nécessaire :

 
Sélectionnez
module.exports = function foo(streamOrPath, callback) {
  if (typeof streamOrPath === 'string') {
    stream = fs.createReadStream(streamOrPath);
  } else if (streamOrPath.pipe && streamOrPath.readable) {
    stream = streamOrPath;
  } else {
    throw new TypeError('foo ne peut être appelé qu\'avec un flux ou un chemin d\'accès');
  }

  // faire ce que l'on veut avec le flux
};

IV. Streamin

Voilà, c'est vraiment simple, non ? Si simple que j'ai créé un plugin juste pour ce cas d'utilisation courante : streaminstreamin.

 
Sélectionnez
var streamin = require('streamin');

module.exports = function foo(streamOrPath, callback) {
  var stream = streamin(streamOrPath);
  
  // faire ce que l'on veut avec le flux
};


Ne vous laissez pas abuser par son nom, streamin fonctionne également avec des flux de sortie.

V. La suite

Dans la prochaine partie, je vais vous montrer comment les modules de type RequestRequest retournent des flux synchrones même lorsqu'ils ne sont pas immédiatement disponibles.

VI. Remerciements

Cet article a été publié avec l'aimable autorisation de Roly Fentanes. L'article original peut être lu sur le site DailyJSDailyJS : Mastering Node Streams: Part 1Mastering Node Streams: Part 1.
Je remercie également Torgar pour sa relecture attentive et assidue.