159 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
		
		
			
		
	
	
			159 lines
		
	
	
		
			5.8 KiB
		
	
	
	
		
			Markdown
		
	
	
	
	
	
|   | --- | |||
|  | title: Streams | |||
|  | localeTitle: Corrientes | |||
|  | --- | |||
|  | ## Corrientes
 | |||
|  | 
 | |||
|  | Las secuencias están disponibles en la API central de Node.js como objetos que permiten que los datos se lean o escriban de forma continua. Básicamente, una secuencia hace eso en trozos en comparación con el búfer que hace su bit a bit, por lo que es un proceso lento. | |||
|  | 
 | |||
|  | Hay cuatro tipos de flujos disponibles: | |||
|  | 
 | |||
|  | *   Legible (flujos desde los cuales se leen los datos) | |||
|  | *   Escritable (flujos en los que se escriben los datos) | |||
|  | *   Dúplex (secuencias que se pueden leer y escribir) | |||
|  | *   Transformar (transmisiones dúplex que pueden modificar datos a medida que se leen y escriben) | |||
|  | 
 | |||
|  | Cada tipo disponible tiene varios métodos asociados. Algunos de los más comunes son: | |||
|  | 
 | |||
|  | *   datos (esto se ejecuta cuando los datos están disponibles) | |||
|  | *   final (esto se activa cuando no hay datos para leer) | |||
|  | *   error (esto se ejecuta cuando hay un error al recibir o escribir datos) | |||
|  | 
 | |||
|  | ### Tubo
 | |||
|  | 
 | |||
|  | En programación, el concepto de `pipe` no es nuevo. Los sistemas basados en Unix han estado usándolo pragmáticamente desde la década de 1970. ¿Qué hace un tubo? Una `pipe` generalmente conecta la fuente y el destino. Pasa la salida de una función como la entrada de otra función. | |||
|  | 
 | |||
|  | En Node.js, la `pipe` se usa de la misma manera, para emparejar entradas y salidas de diferentes operaciones. `pipe()` está disponible como una función que toma un flujo de origen legible y adjunta la salida a un flujo de destino. La sintaxis general se puede representar como: | |||
|  | 
 | |||
|  | ```javascript | |||
|  | src.pipe(dest);  | |||
|  | ``` | |||
|  | 
 | |||
|  | Múltiples funciones `pipe()` también pueden ser encadenadas juntas. | |||
|  | 
 | |||
|  | ```javascript | |||
|  | a.pipe(b).pipe(c);  | |||
|  |   | |||
|  |  // which is equivalent to  | |||
|  |   | |||
|  |  a.pipe(b);  | |||
|  |  b.pipe(c);  | |||
|  | ``` | |||
|  | 
 | |||
|  | ### Corrientes legibles
 | |||
|  | 
 | |||
|  | Los flujos que producen datos que se pueden adjuntar como entrada a un flujo grabable se conocen como flujo legible. Para crear un flujo legible: | |||
|  | 
 | |||
|  | ```javascript | |||
|  | const { Readable } = require('stream');  | |||
|  |   | |||
|  |  const readable = new Readable();  | |||
|  |   | |||
|  |  readable.on('data', chunk => {  | |||
|  |   console.log(`Received ${chunk.length} bytes of data.`);  | |||
|  |  });  | |||
|  |  readable.on('end', () => {  | |||
|  |   console.log('There will be no more data.');  | |||
|  |  });  | |||
|  | ``` | |||
|  | 
 | |||
|  | ### Secuencia de escritura
 | |||
|  | 
 | |||
|  | Este es el tipo de flujo al que puede `pipe()` los datos desde una fuente legible. Para crear un flujo de escritura, tenemos un enfoque de constructor. Creamos un objeto a partir de él y pasamos una serie de opciones. El método toma tres argumentos: | |||
|  | 
 | |||
|  | *   chunk: un buffer | |||
|  | *   codificación: para convertir datos a un formato legible por humanos | |||
|  | *   devolución de llamada: una función que se llama cuando los datos se procesan desde el fragmento | |||
|  | 
 | |||
|  | ```javascript | |||
|  | const { Writable } = require('stream');  | |||
|  |  const writable = new Writable({  | |||
|  |   write(chunk, encoding, callback) {  | |||
|  |     console.log(chunk.toString());  | |||
|  |     callback();  | |||
|  |   }  | |||
|  |  });  | |||
|  |   | |||
|  |  process.stdin.pipe(writable);  | |||
|  | ``` | |||
|  | 
 | |||
|  | ### Streams Duplex
 | |||
|  | 
 | |||
|  | Los flujos dúplex nos ayudan a implementar flujos legibles y grabables al mismo tiempo. | |||
|  | 
 | |||
|  | ```javascript | |||
|  | const { Duplex } = require('stream');  | |||
|  |   | |||
|  |  const inoutStream = new Duplex({  | |||
|  |   write(chunk, encoding, callback) {  | |||
|  |     console.log(chunk.toString());  | |||
|  |     callback();  | |||
|  |   },  | |||
|  |   | |||
|  |   read(size) {  | |||
|  |     this.push(String.fromCharCode(this.currentCharCode++));  | |||
|  |     if (this.currentCharCode > 90) {  | |||
|  |       this.push(null);  | |||
|  |     }  | |||
|  |   }  | |||
|  |  });  | |||
|  |   | |||
|  |  inoutStream.currentCharCode = 65;  | |||
|  |  process.stdin.pipe(inoutStream).pipe(process.stdout);  | |||
|  | ``` | |||
|  | 
 | |||
|  | El flujo `stdin` canaliza los datos legibles en el flujo dúplex. El `stdout` nos ayuda a ver los datos. Las partes legibles y grabables de un flujo dúplex operan completamente independientes entre sí. | |||
|  | 
 | |||
|  | ### Corriente de transformación
 | |||
|  | 
 | |||
|  | Este tipo de flujo es más una versión avanzada del flujo dúplex. | |||
|  | 
 | |||
|  | ```javascript | |||
|  | const { Transform } = require('stream');  | |||
|  |   | |||
|  |  const upperCaseTr = new Transform({  | |||
|  |   transform(chunk, encoding, callback) {  | |||
|  |     this.push(chunk.toString().toUpperCase());  | |||
|  |     callback();  | |||
|  |   }  | |||
|  |  });  | |||
|  |   | |||
|  |  process.stdin.pipe(upperCaseTr).pipe(process.stdout);  | |||
|  | ``` | |||
|  | 
 | |||
|  | Los datos que estamos consumiendo son los mismos que en el ejemplo anterior de la transmisión dúplex. Lo que hay que notar aquí es que `transform()` no requiere la implementación de métodos de `read` o `write` . Combina ambos métodos en sí. | |||
|  | 
 | |||
|  | ### ¿Por qué usar Streams?
 | |||
|  | 
 | |||
|  | Dado que Node.js es asíncrono, interactúa pasando devoluciones de llamada a funciones con disco y red. Un ejemplo dado a continuación lee los datos de un archivo en el disco y los responde a través de la solicitud de red del cliente. | |||
|  | 
 | |||
|  | ```javascript | |||
|  | const http = require('http');  | |||
|  |  const fs = require('fs');  | |||
|  |   | |||
|  |  const server = http.createServer((req, res) => {  | |||
|  |   fs.readFile('data.txt', (err, data) => {  | |||
|  |     res.end(data);  | |||
|  |   });  | |||
|  |  });  | |||
|  |  server.listen(8000);  | |||
|  | ``` | |||
|  | 
 | |||
|  | El fragmento de código anterior funcionará, pero todos los datos del archivo irán primero a la memoria para cada solicitud antes de volver a escribir el resultado en la solicitud del cliente. Si el archivo que estamos leyendo es demasiado grande, esto puede convertirse en una llamada de servidor muy pesada y costosa, ya que consumirá una gran cantidad de memoria para que el proceso avance. La experiencia del usuario en el lado del cliente también sufrirá demora. | |||
|  | 
 | |||
|  | En este caso, si utilizamos secuencias, los datos se enviarán a la solicitud del cliente como una parte a la vez, tan pronto como se reciban del disco. | |||
|  | 
 | |||
|  | ```javascript | |||
|  | const http = require('http');  | |||
|  |  const fs = require('fs');  | |||
|  |   | |||
|  |  const server = http.createServer((req, res) => {  | |||
|  |   const stream = fs.createReadStream('data.txt');  | |||
|  |   stream.pipe(res);  | |||
|  |  });  | |||
|  |  server.listen(8000);  | |||
|  | ``` | |||
|  | 
 | |||
|  | El `pipe()` aquí se ocupa de la escritura o, en nuestro caso, el envío de los datos con el objeto de respuesta y una vez que se leen todos los datos del archivo, para cerrar la conexión. | |||
|  | 
 | |||
|  | Nota: `process.stdin` y `process.stdout` se crean en secuencias en el objeto de `process` global proporcionado por la API Node.js. |