Las transmisiones en Node.js pueden ser complicadas, pero vale la pena tomarse su tiempo para comprenderlas.
Conclusiones clave
- Los flujos en Node.js son una herramienta fundamental para el procesamiento y la transferencia de datos, lo que los hace ideales para aplicaciones en tiempo real y basadas en eventos.
- Para crear una secuencia de escritura en Node.js, puede usar la función createWriteStream() del módulo fs, que escribe datos en una ubicación específica.
- Legible, escribible, dúplex y transformada son los cuatro tipos de flujos en Node.js, cada uno con su propio caso de uso y funcionalidad.
Una secuencia es una herramienta de programación fundamental que se ocupa del flujo de datos. En esencia, una secuencia normalmente representa la transferencia secuencial de bytes de un punto a otro. La documentación oficial de Node.js define una secuencia como una interfaz abstracta que puedes usar para trabajar con datos.
Transferir datos en una computadora o a través de una red es un uso ideal de una transmisión.
Secuencias en Node.js
Las transmisiones han jugado un papel esencial en el éxito de Node.js. Son ideales para el procesamiento de datos en tiempo real y aplicaciones controladas por eventos, dos características destacadas del entorno de ejecución de Node.js.
Para crear una nueva transmisión en Node.js, necesitará usar la API de transmisión, que funciona exclusivamente con cadenas y Datos del búfer de Node.js. Node.js tiene cuatro tipos de transmisiones: escribibles, legibles, dúplex y transformadas.
Cómo crear y utilizar una secuencia grabable
Una secuencia grabable le permite escribir o enviar datos a una ubicación específica. El módulo fs (sistema de archivos) tiene una clase WriteStream, que puede usar para crear una nueva secuencia con el fs.createWriteStream() función. Esta función acepta la ruta al archivo en el que desea escribir datos, así como una serie opcional de opciones.
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();
})();
Este código importa el crearWriteStream() función, que la función de flecha anónima luego se usa para crear una secuencia que escribe datos en myFile.txt. La función anónima contiene una función interna llamada escribirDatos() que escribe datos.
El crearWriteStream() La función funciona con un búfer para escribir una colección de números (0–9999) en el archivo de destino. Sin embargo, cuando ejecuta el script anterior, crea un archivo en el mismo directorio que contiene los siguientes datos:
La colección actual de números termina en 2.915, pero debería haber incluido números hasta 9.999. Esta discrepancia se produce porque cada WriteStream utiliza un búfer que almacena una cantidad fija de datos a la vez. Para saber cuál es este valor predeterminado, deberá consultar el alta marca de agua opción.
console.log("The highWaterMark value is: " +
myWriteStream.writableHighWaterMark + " bytes.");
Agregar la línea de código anterior a la función anónima producirá el siguiente resultado en la terminal:
La salida del terminal muestra que el valor predeterminado alta marca de agua El valor (que es personalizable) es 16.384 bytes. Esto significa que solo puede almacenar menos de 16.384 bytes de datos en este búfer a la vez. Entonces, hasta el número 2915 (más todas las comas y espacios) representa la cantidad máxima de datos que el búfer puede almacenar a la vez.
La solución al error del búfer es utilizar un evento de transmisión. Una secuencia encuentra varios eventos en distintas etapas del proceso de transferencia de datos. El drenar event es la opción adecuada para esta situación.
En el escribirDatos() función anterior, la llamada al Escritura de WriteStream () La función devuelve verdadero si el fragmento de datos (o el búfer interno) está por debajo del alta marca de agua valor. Esto indica que la aplicación puede enviar más datos a la transmisión. Sin embargo, tan pronto como el escribir() La función devuelve falso, el bucle se rompe porque necesita drenar el búfer.
myWriteStream.on('drain', () => {
console.log("a drain has occurred...");
writeData();
});
Insertando el drenar El código de evento anterior en la función anónima vaciará el Búfer de WriteStream cuando esté al máximo de su capacidad. Luego, recuerda el escribirDatos() método, para que pueda continuar escribiendo datos. La ejecución de la aplicación actualizada producirá el siguiente resultado:
Debes tener en cuenta que la aplicación tenía que drenar el Búfer de escritura tres veces durante su ejecución. El archivo de texto también experimentó algunos cambios:
Cómo crear y utilizar una transmisión legible
Para leer datos, comience creando una secuencia legible usando el fs.createReadStream() función.
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.");
});
})();
El script anterior utiliza el crearReadStream() método para acceder al archivo que creó el código anterior: myFile.txt. El crearReadStream() La función acepta una ruta de archivo (que puede tener la forma de una cadena, un búfer o una URL) y varias opciones opcionales como argumentos.
En la función anónima, hay varios eventos de transmisión importantes. Sin embargo, no hay señales de la drenar evento. Esto se debe a que una secuencia legible solo almacena datos en el buffer cuando llamas al flujo.push (trozo) funcionar o utilizar el legible evento.
El abierto El evento se activa cuando fs abre el archivo que desea leer. Cuando adjuntas el datos evento a una secuencia implícitamente continua, hace que la secuencia pase al modo de flujo. Esto permite que los datos pasen tan pronto como estén disponibles. Al ejecutar la aplicación anterior se produce el siguiente resultado:
Cómo crear y utilizar una transmisión dúplex
Una secuencia dúplex implementa las interfaces de secuencia legible y de escritura, por lo que puede leer y escribir en dicha secuencia. Un ejemplo es un socket TCP que depende del módulo net para su creación.
Una forma sencilla de demostrar las propiedades de una transmisión dúplex es crear un servidor y un cliente TCP que transfiera datos.
El archivo server.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);
});
El archivo 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.');
});
Notará que tanto los scripts del servidor como del cliente utilizan una secuencia legible y grabable para comunicarse (transferir y recibir datos). Naturalmente, la aplicación del servidor se ejecuta primero y comienza a escuchar las conexiones. Tan pronto como inicia el cliente, se conecta al servidor usando el número de puerto TCP.
Después de establecer una conexión, el cliente inicia la transferencia de datos escribiendo al servidor usando su Corriente de escritura. El servidor registra los datos que recibe en el terminal y luego escribe los datos utilizando su WriteStream. Finalmente, el cliente registra los datos que recibe, escribe datos adicionales y luego se desconecta del servidor. El servidor permanece abierto para que otros clientes se conecten.
Cómo crear y utilizar una secuencia de transformación
Los flujos de transformación son flujos dúplex en los que la salida está relacionada con la entrada, pero es diferente de ella. Node.js tiene dos tipos de flujos Transform: flujos zlib y cripto. Una secuencia zlib puede comprimir un archivo de texto y luego descomprimirlo después de la transferencia del archivo.
La aplicación 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);
})();
Este sencillo script toma el archivo de texto original, lo comprime y lo almacena en el directorio actual. Este es un proceso simple gracias a la transmisión legible. tubo() método. Las canalizaciones de flujo eliminan el uso de buffers y canalizan datos directamente de un flujo a otro.
Sin embargo, antes de que los datos lleguen a la secuencia de escritura en el script, se necesita un pequeño desvío a través del método createGzip() de zlib. Este método comprime el archivo y devuelve un nuevo objeto Gzip que luego recibe la secuencia de escritura.
La aplicación 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);
})();
Este script anterior toma el archivo comprimido y lo descomprime. Si abres el nuevo miArchivo2.txt archivo, verás que contiene los mismos datos que el archivo original:
¿Por qué son importantes las transmisiones?
Los flujos mejoran la eficiencia de la transferencia de datos. Los flujos de lectura y escritura sirven como base que permite la comunicación entre clientes y servidores, así como la compresión y transferencia de archivos de gran tamaño.
Los flujos también mejoran el rendimiento de los lenguajes de programación. Sin transmisiones, el proceso de transferencia de datos se vuelve más complejo, lo que requiere una mayor participación manual de los desarrolladores y genera más errores y problemas de rendimiento.