1. Analyse d'ouverture
Stream est une interface abstraite implémentée par de nombreux objets dans Node. Par exemple, une demande à un serveur HTTP est un flux, et STDOUT est également un flux. Les flux sont lisibles, écrits ou les deux.
Le premier contact avec Stream a commencé avec le début Unix. Des décennies de pratique ont prouvé que l'idée de Stream peut simplement développer des systèmes énormes.
Dans Unix, Stream est implémenté via "|". Dans le nœud, en tant que module de flux intégré, de nombreux modules de base et des modules tripartites sont utilisés.
Comme UNIX, le fonctionnement principal du flux de nœuds est .pipe (), et les utilisateurs peuvent utiliser le mécanisme de contre-pression pour contrôler l'équilibre entre la lecture et l'écriture.
Stream peut fournir aux développeurs une interface unifiée qui peut réutiliser et contrôler l'équilibre de lecture et d'écriture entre les flux via des interfaces de flux abstraites.
Une connexion TCP est à la fois un flux lisible et un flux écrit, tandis qu'une connexion HTTP est différente. Un objet de demande HTTP est un flux lisible, tandis qu'un objet de réponse HTTP est un flux écrite.
Le processus de transmission du flux est transmis sous la forme d'un tampon par défaut, à moins que vous ne définisse d'autres formulaires de codage pour celui-ci, ce qui suit est un exemple:
La copie de code est la suivante:
var http = require ('http');
var server = http.createServer (fonction (req, res) {
res.writeHeader (200, {'Content-Type': 'Text / PLAIN'});
res.end ("Bonjour, Big Bear!");
});
server.Listen (8888);
console.log ("Http Server fonctionnant sur le port 8888 ...");
Après l'exécution, le code brouillé apparaîtra car le jeu de caractères spécifié n'est pas défini, tel que: "UTF-8".
Modifiez-le simplement:
La copie de code est la suivante:
var http = require ('http');
var server = http.createServer (fonction (req, res) {
res.writeHeader (200, {
'Content-Type': 'Text / PLAIN; charset = utf-8' // ajouter charset = utf-8
});
res.end ("Bonjour, Big Bear!");
});
server.Listen (8888);
console.log ("Http Server fonctionnant sur le port 8888 ...");
Résultats en cours:
Pourquoi utiliser le flux
Les E / S dans le nœud sont asynchrones, donc la lecture et l'écriture sur le disque et le réseau nécessitent des données de lecture et de lecture via des fonctions de rappel. Ce qui suit est un exemple de téléchargement de fichiers
Sur le code:
La copie de code est la suivante:
var http = require ('http');
var fs = require ('fs');
var server = http.createServer (fonction (req, res) {
fs.readfile (__ dirname + '/data.txt', fonction (err, data) {
res.end (données);
});
});
server.Listen (8888);
Le code peut implémenter les fonctions requises, mais le service doit mettre en mémoire l'ensemble des données de fichier avant d'envoyer les données du fichier. Si le fichier "data.txt" est très
S'il est grand et a une grande concurrence, beaucoup de mémoire sera gaspillée. Étant donné que l'utilisateur doit attendre que l'ensemble du fichier soit mis en cache en mémoire pour accepter les données du fichier, cela conduit à
L'expérience utilisateur est assez mauvaise. Heureusement, les deux paramètres (req, res) sont du flux, nous pouvons donc utiliser fs.creareAdStream () au lieu de fs.readfile (). comme suit:
La copie de code est la suivante:
var http = require ('http');
var fs = require ('fs');
var server = http.createServer (fonction (req, res) {
var stream = fs.createadStream (__ dirname + '/data.txt');
Stream.Pipe (RES);
});
server.Listen (8888);
La méthode .Pipe () écoute les événements «données» et «fin» de fs.creareAdStream (), de sorte que le fichier "data.txt" n'a pas besoin d'être mis en cache.
Un fichier peut être envoyé au client immédiatement une fois la connexion client terminée. Un autre avantage de l'utilisation de .pipe () est qu'il peut être résolu lorsqu'un client
Lisez et écrivez un déséquilibre causé par un très grand retard final.
Il y a cinq flux de base: lisibles, écrivables, transformés, duplex et "classiques". (Veuillez vérifier l'API pour plus de détails)
2. Introduire des exemples
Lorsque les données qui doivent être traitées ne peuvent pas être chargées en mémoire en même temps, ou lorsque le traitement est plus efficace pendant la lecture, nous devons utiliser des flux de données. NodeJS fournit des opérations sur les flux de données via divers flux.
Prenant l'exemple du programme de copie de fichiers importante, nous pouvons créer un flux de données en lecture seule pour la source de données, l'exemple est le suivant:
La copie de code est la suivante:
var rs = fs.creareAdStream (pathName);
Rs.on ('data', fonction (chunk) {
Dosomething (morceau); // utilise les détails spécifiques comme vous le souhaitez
});
Rs.on ('end', function () {
nettoyage ();
});
Les événements de données dans le code seront déclenchés en continu, que la fonction de dosage peut être traitée. Le code peut être modifié comme suit pour résoudre ce problème.
La copie de code est la suivante:
var rs = fs.creareAdStream (src);
Rs.on ('data', fonction (chunk) {
Rs.Pause ();
Dosomething (Chunk, function () {
Rs.Resume ();
});
});
Rs.on ('end', function () {
nettoyage ();
});
Un rappel est ajouté à la fonction Dosomething, afin que nous puissions mettre en pause la lecture des données avant de traiter les données et continuer à lire les données après le traitement des données.
De plus, nous pouvons également créer un flux de données d'écriture uniquement pour la cible de données, comme suit:
La copie de code est la suivante:
var rs = fs.creareAdStream (src);
var ws = fs.CreateWRiteStream (DST);
Rs.on ('data', fonction (chunk) {
ws.Write (morceau);
});
Rs.on ('end', function () {
ws.end ();
});
Une fois que Dosomething a été remplacé par l'écriture de données dans le flux d'écriture uniquement, le code ci-dessus ressemble à un programme de copie de fichiers. Cependant, le code ci-dessus a les problèmes mentionnés ci-dessus. Si la vitesse d'écriture ne peut pas suivre la vitesse de lecture, l'écriture du cache uniquement dans le flux de données explosera. Nous pouvons juger si les données entrantes ont été écrites sur la cible ou temporairement placées dans le cache en fonction de la valeur de retour de la méthode .write, et juger lorsque seules les données d'écriture ont été écrites sur la cible en fonction de l'événement de drainage, et passer dans les données suivantes. Par conséquent, le code est le suivant:
La copie de code est la suivante:
var rs = fs.creareAdStream (src);
var ws = fs.CreateWRiteStream (DST);
Rs.on ('data', fonction (chunk) {
if (ws.write (chunk) === false) {
Rs.Pause ();
}
});
Rs.on ('end', function () {
ws.end ();
});
ws.on ('drainer', fonction () {
Rs.Resume ();
});
Enfin, le transfert de données du flux de données en lecture seule au flux de données en écriture est réalisé, et le contrôle de l'entrepôt à l'épreuve des explosions est inclus. Étant donné qu'il existe de nombreux scénarios d'utilisation, tels que le programme de copie de fichiers grand ci-dessus, NodeJS fournit directement la méthode .pipe pour ce faire, et sa méthode d'implémentation interne est similaire au code ci-dessus.
Voici un processus plus complet de copie de fichiers:
La copie de code est la suivante:
var fs = require ('fs'),
path = require ('path'),
out = process.stdout;
var filepath = '/bb/bigbear.mkv';
var readStream = fs.creareAdStream (filepath);
var writeStream = fs.createwRiteStream ('file.mkv');
var stat = fsatSync (filepath);
var totalSize = stat.size;
var passLength = 0;
var dure = 0;
var starttime = date.Now ();
readStream.on ('data', fonction (chunk) {
passingLength + = chunk.length;
if (writeStream.write (chunk) === false) {
readStream.pause ();
}
});
readStream.on ('end', function () {
writeStream.end ();
});
writeStream.on ('drain', function () {
readStream.Resume ();
});
setTimeout (fonction show () {
var pour cent = math.ceil ((passhengle / totalSize) * 100);
var size = math.ceil (passlength / 1000000);
var diff = taille - dure;
dure = taille;
Out.Clearline ();
out.cursorto (0);
out.write ('terminé' + taille + 'mb,' + pour cent + '%, vitesse:' + diff * 2 + 'mb / s');
if (passlength <totalSize) {
setTimeout (show, 500);
} autre {
var endtime = date.Now ();
console.log ();
console.log ('lorsque partagé:' + (EndTime - starttime) / 1000 + 'secondes.');
}
}, 500);
Vous pouvez enregistrer le code ci-dessus comme "copy.js". Expérience: Nous avons ajouté un SetTimeout récursif (ou utiliser directement SetInterval) pour être un spectateur.
Observez les progrès de l'achèvement toutes les 500 ms et écrivez la taille, le pourcentage et la vitesse de copie terminés ensemble sur la console. Une fois la copie terminée, le temps total est calculé.
Trois, résumons
(1) Comprendre le concept de flux.
(2) compétent dans l'utilisation de l'API de flux pertinent
(3) Faites attention au contrôle des détails, tels que: copier des fichiers volumineux, en utilisant la forme de "données de morceaux" pour la rupture.
(4), l'utilisation du tuyau
(5), mettez à nouveau l'accent sur un concept: une connexion TCP est à la fois un flux lisible et un flux écrivative, tandis qu'une connexion HTTP est différente. Un objet de demande HTTP est un flux lisible, tandis qu'un objet de réponse HTTP est un flux écrite.