Les flux dans Node.js peuvent être compliqués, mais cela vaut la peine de prendre le temps de les comprendre.
Points clés à retenir
- Les flux dans Node.js constituent un outil fondamental pour le traitement et le transfert de données, ce qui les rend idéaux pour les applications en temps réel et basées sur des événements.
- Pour créer un flux inscriptible dans Node.js, vous pouvez utiliser la fonction createWriteStream() du module fs, qui écrit les données dans un emplacement spécifique.
- Lisible, inscriptible, duplex et transformé sont les quatre types de flux dans Node.js, chacun avec son propre cas d'utilisation et ses propres fonctionnalités.
Un flux est un outil de programmation fondamental qui gère le flux de données. À la base, un flux représente généralement le transfert séquentiel d’octets d’un point à un autre. La documentation officielle de Node.js définit un flux comme une interface abstraite que vous pouvez utiliser pour travailler avec des données.
Le transfert de données sur un ordinateur ou sur un réseau est une utilisation idéale d'un flux.
Flux dans Node.js
Les streams ont joué un rôle essentiel dans le succès de Node.js. Ils sont idéaux pour le traitement des données en temps réel et les applications basées sur des événements, deux fonctionnalités importantes de l'environnement d'exécution Node.js.
Pour créer un nouveau flux dans Node.js, vous devrez utiliser l'API de flux, qui fonctionne exclusivement avec les chaînes et Données du tampon Node.js. Node.js propose quatre types de flux: inscriptible, lisible, duplex et transformé.
Comment créer et utiliser un flux inscriptible
Un flux inscriptible vous permet d'écrire ou d'envoyer des données vers un emplacement spécifique. Le module fs (système de fichiers) possède une classe WriteStream, que vous pouvez utiliser pour créer un nouveau flux avec le fs.createWriteStream() fonction. Cette fonction accepte le chemin d'accès au fichier dans lequel vous souhaitez écrire des données, ainsi qu'un tableau facultatif d'options.
const {createWriteStream} = require("fs");(() => {
const file = "myFile.txt";
const myWriteStream = createWriteStream(file);
let x = 0;
const writeNumber = 10000;
const writeData = () => {
while (x < writeNumber) {
const chunk = Buffer.from(`${x}, `, "utf-8");
if (x writeNumber - 1) return myWriteStream.end(chunk);
if (!myWriteStream.write(chunk)) break;
x++
}
};
writeData();
})();
Ce code importe le créerWriteStream() fonction, qui la fonction flèche anonyme utilise ensuite pour créer un flux qui écrit des données dans myFile.txt. La fonction anonyme contient une fonction interne appelée writeData() qui écrit des données.
Le créerWriteStream() La fonction fonctionne avec un tampon pour écrire une collection de nombres (0 à 9 999) dans le fichier de destination. Cependant, lorsque vous exécutez le script ci-dessus, il crée un fichier dans le même répertoire contenant les données suivantes :
La collection actuelle de numéros se termine à 2 915, mais elle aurait dû inclure des numéros allant jusqu'à 9 999. Cette différence se produit car chaque WriteStream utilise un tampon qui stocke une quantité fixe de données à la fois. Pour connaître cette valeur par défaut, vous devrez consulter le marque d'eau élevée option.
console.log("The highWaterMark value is: " +
myWriteStream.writableHighWaterMark + " bytes.");
L'ajout de la ligne de code ci-dessus à la fonction anonyme produira le résultat suivant dans le terminal :
La sortie du terminal montre que la valeur par défaut marque d'eau élevée la valeur (qui est personnalisable) est de 16 384 octets. Cela signifie que vous ne pouvez stocker que moins de 16 384 octets de données à la fois dans ce tampon. Ainsi, jusqu'au nombre 2 915 (plus toutes les virgules et espaces) représente la quantité maximale de données que le tampon peut stocker en même temps.
La solution à l'erreur de tampon consiste à utiliser un événement de flux. Un flux rencontre divers événements à des étapes distinctes du processus de transfert de données. Le vidange l'événement est l'option appropriée pour cette situation.
Dans le writeData() fonction ci-dessus, l'appel au Write() de WriteStream la fonction renvoie vrai si le morceau de données (ou le tampon interne) est inférieur au marque d'eau élevée valeur. Cela indique que l'application peut envoyer plus de données au flux. Cependant, dès que le écrire() La fonction renvoie false, la boucle est interrompue car vous devez vider le tampon.
myWriteStream.on('drain', () => {
console.log("a drain has occurred...");
writeData();
});
Insérer le vidange le code d'événement ci-dessus dans la fonction anonyme videra le Le tampon de WriteStream quand il est à pleine capacité. Ensuite, il rappelle le writeData() méthode, afin qu’il puisse continuer à écrire des données. L'exécution de l'application mise à jour produira le résultat suivant :
Il convient de noter que l'application a dû vider le Tampon WriteStream trois fois au cours de son exécution. Le fichier texte a également connu quelques changements :
Comment créer et utiliser un flux lisible
Pour lire des données, commencez par créer un flux lisible à l'aide du fs.createReadStream() fonction.
const {createReadStream} = require("fs");
(() => {
const file = "myFile.txt";
const myReadStream = createReadStream(file);myReadStream.on("open", () => {
console.log(`The read stream has successfully opened ${file}.`);
});myReadStream.on("data", chunk => {
console.log("The file contains the following data: " + chunk.toString());
});
myReadStream.on("close", () => {
console.log("The file has been successfully closed.");
});
})();
Le script ci-dessus utilise le créerReadStream() méthode pour accéder au fichier créé par le code précédent: myFile.txt. Le créerReadStream() La fonction accepte un chemin de fichier (qui peut être sous la forme d'une chaîne, d'un tampon ou d'une URL) et plusieurs options facultatives comme arguments.
Dans la fonction anonyme, il existe plusieurs événements de flux importants. Cependant, il n'y a aucun signe de vidange événement. En effet, un flux lisible ne met en mémoire tampon les données que lorsque vous appelez le stream.push (morceau) fonction ou utilisez le lisible événement.
Le ouvrir l'événement se déclenche lorsque fs ouvre le fichier que vous souhaitez lire. Lorsque vous attachez le données événement à un flux implicitement continu, cela provoque la transition du flux en mode fluide. Cela permet aux données de transiter dès qu'elles deviennent disponibles. L'exécution de l'application ci-dessus produit le résultat suivant :
Comment créer et utiliser un flux duplex
Un flux duplex implémente à la fois les interfaces de flux inscriptibles et lisibles, afin que vous puissiez lire et écrire dans un tel flux. Un exemple est un socket TCP qui s'appuie sur le module net pour sa création.
Un moyen simple de démontrer les propriétés d'un flux duplex consiste à créer un serveur et un client TCP qui transfèrent les données.
Le fichier serveur.js
const net = require('net');
const port = 5000;
const host = '127.0.0.1';const server = net.createServer();
server.on('connection', (socket)=> {
console.log('Connection established from client.');socket.on('data', (data) => {
console.log(data.toString());
});socket.write("Hi client, I am server " + server.address().address);
socket.on('close', ()=> {
console.log('the socket is closed')
});
});
server.listen(port, host, () => {
console.log('TCP server is running on port: ' + port);
});
Le fichier client.js
const net = require('net');
const client = new net.Socket();
const port = 5000;
const host = '127.0.0.1';client.connect(port, host, ()=> {
console.log("connected to server!");
client.write("Hi, I'm client " + client.address().address);
});client.on('data', (data) => {
console.log(data.toString());
client.write("Goodbye");
client.end();
});
client.on('end', () => {
console.log('disconnected from server.');
});
Vous remarquerez que les scripts serveur et client utilisent un flux lisible et inscriptible pour communiquer (transférer et recevoir des données). Naturellement, l'application serveur s'exécute en premier et commence à écouter les connexions. Dès que vous démarrez le client, il se connecte au serveur en utilisant le numéro de port TCP.
Après avoir établi une connexion, le client lance le transfert de données en écrivant sur le serveur à l'aide de son ÉcrireStream. Le serveur enregistre les données qu'il reçoit sur le terminal, puis écrit les données à l'aide de son WriteStream. Enfin, le client enregistre les données qu'il reçoit, écrit des données supplémentaires, puis se déconnecte du serveur. Le serveur reste ouvert pour que d'autres clients puissent se connecter.
Comment créer et utiliser un flux de transformation
Les flux de transformation sont des flux duplex dans lesquels la sortie est liée à l'entrée, mais différente de celle-ci. Node.js propose deux types de flux de transformation: les flux zlib et crypto. Un flux zlib peut compresser un fichier texte puis le décompresser après le transfert de fichier.
L'application compressFile.js
const zlib = require('zlib');
const { createReadStream, createWriteStream } = require('fs');(() => {
const source = createReadStream('myFile.txt');
const destination = createWriteStream('myFile.txt.gz');
source.pipe(zlib.createGzip()).pipe(destination);
})();
Ce script simple prend le fichier texte original, le compresse et le stocke dans le répertoire actuel. C'est un processus simple grâce au flux lisible tuyau() méthode. Les pipelines de flux suppriment l’utilisation de tampons et redirigent les données directement d’un flux à un autre.
Cependant, avant que les données n'atteignent le flux inscriptible dans le script, il faut un petit détour via la méthode createGzip() de zlib. Cette méthode compresse le fichier et renvoie un nouvel objet Gzip que le flux d'écriture reçoit ensuite.
L'application decompressFile.js
const zlib = require('zlib');
const { createReadStream, createWriteStream } = require('fs');
(() => {
const source = createReadStream('myFile.txt.gz');
const destination = createWriteStream('myFile2.txt');
source.pipe(zlib.createUnzip()).pipe(destination);
})();
Ce script ci-dessus prend le fichier compressé et le décompresse. Si vous ouvrez le nouveau monFichier2.txt fichier, vous verrez qu’il contient les mêmes données que le fichier d’origine :
Pourquoi les flux sont-ils importants?
Les flux améliorent l’efficacité du transfert de données. Les flux lisibles et inscriptibles servent de base à la communication entre les clients et les serveurs, ainsi qu'à la compression et au transfert de fichiers volumineux.
Les flux améliorent également les performances des langages de programmation. Sans flux, le processus de transfert de données devient plus complexe, nécessitant une plus grande saisie manuelle de la part des développeurs et entraînant davantage d'erreurs et de problèmes de performances.