Secuencias de Node.js

Descubra para qué sirven las transmisiones, por qué son tan importantes y cómo utilizarlas.

Que son las corrientes

Las transmisiones son uno de los conceptos fundamentales que impulsan las aplicaciones de Node.js.

Son una forma de manejar archivos de lectura / escritura, comunicaciones de red o cualquier tipo de intercambio de información de un extremo a otro de una manera eficiente.

Las transmisiones no son un concepto exclusivo de Node.js. Fueron introducidos en el sistema operativo Unix hace décadas, y los programas pueden interactuar entre sí pasando flujos a través del operador de tubería (|).

Por ejemplo, de la manera tradicional, cuando le dice al programa que lea un archivo, el archivo se lee en la memoria, de principio a fin, y luego lo procesa.

Utilizando secuencias, lo lees pieza por pieza, procesando su contenido sin guardarlo todo en la memoria.

El Node.jsstreammóduloproporciona la base sobre la que se construyen todas las API de transmisión.

Por que streams

Las transmisiones ofrecen básicamente dos ventajas importantes al utilizar otros métodos de manejo de datos:

  • Eficiencia de la memoria: no necesita cargar grandes cantidades de datos en la memoria antes de poder procesarlos
  • Eficiencia de tiempo: toma mucho menos tiempo comenzar a procesar datos tan pronto como los tiene, en lugar de esperar hasta que toda la carga útil de datos esté disponible para comenzar

Un ejemplo de una corriente

Un ejemplo típico es el de leer archivos de un disco.

Usando el nodofsmódulo puede leer un archivo y servirlo a través de HTTP cuando se establece una nueva conexión a su servidor http:

const http = require('http')
const fs = require('fs')

const server = http.createServer(function (req, res) { fs.readFile(__dirname + ‘/data.txt’, (err, data) => { res.end(data) }) }) server.listen(3000)

readFile()lee el contenido completo del archivo e invoca la función de devolución de llamada cuando está listo.

res.end(data)en la devolución de llamada devolverá el contenido del archivo al cliente HTTP.

Si el archivo es grande, la operación llevará bastante tiempo. Aquí está escrito lo mismo usando streams:

const http = require('http')
const fs = require('fs')

const server = http.createServer((req, res) => { const stream = fs.createReadStream(__dirname + ‘/data.txt’) stream.pipe(res) }) server.listen(3000)

En lugar de esperar hasta que el archivo se lea por completo, comenzamos a transmitirlo al cliente HTTP tan pronto como tengamos una gran cantidad de datos listos para ser enviados.

tubo()

El ejemplo anterior usa la líneastream.pipe(res): lapipe()se llama al método en la secuencia de archivos.

¿Qué hace este código? Toma la fuente y la canaliza hacia un destino.

Lo llama en la secuencia de origen, por lo que en este caso, la secuencia de archivo se canaliza a la respuesta HTTP.

El valor de retorno de lapipe()método es el flujo de destino, que es algo muy conveniente que nos permite encadenar múltiplespipe()llamadas, así:

src.pipe(dest1).pipe(dest2)

Esta construcción es lo mismo que hacer

src.pipe(dest1)
dest1.pipe(dest2)

API de nodo impulsadas por Streams

Debido a sus ventajas, muchos módulos centrales de Node.js brindan capacidades nativas de manejo de transmisiones, en particular:

  • process.stdindevuelve una secuencia conectada a stdin
  • process.stdoutdevuelve una transmisión conectada a stdout
  • process.stderrdevuelve una transmisión conectada a stderr
  • fs.createReadStream()crea una secuencia legible en un archivo
  • fs.createWriteStream()crea una secuencia de escritura en un archivo
  • net.connect()inicia una conexión basada en flujo
  • http.request()devuelve una instancia de la clase http.ClientRequest, que es una secuencia de escritura
  • zlib.createGzip()comprimir datos usando gzip (un algoritmo de compresión) en una secuencia
  • zlib.createGunzip()descomprimir una secuencia gzip.
  • zlib.createDeflate()comprimir datos usando deflate (un algoritmo de compresión) en una secuencia
  • zlib.createInflate()descomprimir una corriente desinflada

Diferentes tipos de corrientes

Hay cuatro clases de corrientes:

  • Readable: una secuencia desde la que puede canalizar, pero no canalizar (puede recibir datos, pero no enviar datos). Cuando inserta datos en una secuencia legible, se almacena en búfer hasta que un consumidor comienza a leer los datos.
  • Writable: una secuencia a la que puede canalizar, pero no desde (puede enviar datos, pero no recibirlos)
  • Duplex: una secuencia en la que puede canalizar y desde la que puede canalizar, básicamente una combinación de una secuencia legible y escribible
  • Transform: un flujo de transformación es similar a un dúplex, pero la salida es una transformación de su entrada

Cómo crear una secuencia legible

Obtenemos la secuencia legible delstreammódulo, y lo inicializamos

const Stream = require('stream')
const readableStream = new Stream.Readable()

Ahora que la transmisión está inicializada, podemos enviarle datos:

readableStream.push('hi!')
readableStream.push('ho!')

Cómo crear una secuencia de escritura

Para crear una secuencia de escritura, ampliamos la base.Writableobjeto, e implementamos su método _write ().

Primero crea un objeto de flujo:

const Stream = require('stream')
const writableStream = new Stream.Writable()

luego implementar_write:

writableStream._write = (chunk, encoding, next) => {
    console.log(chunk.toString())
    next()
}

Ahora puede canalizar una secuencia legible en:

process.stdin.pipe(writableStream)

Cómo obtener datos de una secuencia legible

¿Cómo leemos los datos de una secuencia legible? Usando una secuencia de escritura:

const Stream = require('stream')

const readableStream = new Stream.Readable() const writableStream = new Stream.Writable()

writableStream._write = (chunk, encoding, next) => { console.log(chunk.toString()) next() }

readableStream.pipe(writableStream)

readableStream.push(‘hi!’) readableStream.push(‘ho!’)

También puede consumir una secuencia legible directamente, utilizando elreadableevento:

readableStream.on('readable', () => {
  console.log(readableStream.read())
})

Cómo enviar datos a una secuencia de escritura

Usando la corrientewrite()método:

writableStream.write('hey!\n')

Señalar una secuencia de escritura que terminó de escribir

Utilizar elend()método:

const Stream = require('stream')

const readableStream = new Stream.Readable() const writableStream = new Stream.Writable()

writableStream._write = (chunk, encoding, next) => { console.log(chunk.toString()) next() }

readableStream.pipe(writableStream)

readableStream.push(‘hi!’) readableStream.push(‘ho!’)

writableStream.end()

Descarga mi gratisManual de Node.js


Más tutoriales de nodos: