No tienes acceso a esta clase

¡Continúa aprendiendo! Únete y comienza a potenciar tu carrera

Streams

25/31
Recursos

Aportes 92

Preguntas 20

Ordenar por:

Los aportes, preguntas y respuestas son vitales para aprender en comunidad. Regístrate o inicia sesión para participar.

Mi aporte de como lo veo:

** Stream**
Podría decirse que un Stream es el proceso de ir consumiendo datos al tiempo en que se reciben. Por ejemplo, cuando vemos un video en Youtube estamos consumiendo datos por medio de streaming (readable stream, porque solo podemos ver los videos mas no editarlos) ya que lo vemos al mismo tiempo en que este se está descargando. de lo contrario habría que esperar a que se descargue el video por completo para poder verlo.

buffer
Si en el caso anterior, mientras vemos el video, fallara el internet, así sea por un segundo, la reproducción se pararía instantáneamente. Pero sabemos que en realidad no es así, el video continúa reproduciéndose por un tiempo mas. Esto es gracias a la implementación de un buffer el cuál es un espacio en memoria ram en donde la información proveniente del servidor llega por fragmentos (chunks), para luego ser consumido, y como ese almacenamiento de datos en el buffer se hace a bajo nivel, de forma binaria, el proceso es mucho mas rápido de lo que se consume. Es por eso que cuando reproducimos un video en Youtube vemos que este se carga mas rápido. (dependiendo del ancho de banda claro está)

intentaré explicarlo para ver si se entiende de mejor manera que wea pasa en esta parte del código

const Transform = stream.Transform;

lo que se hace aquí es crear una constante que va a contener la clase Transform, pero… que es lo que hace Transform?.
pues básicamente lo que hace es transformar la secuencia de entrada para que la secuencia de salida sea una diferente. EJ: ( no falta el weon que se lo olvida que las iniciales de los nombres van en Mayúsculas, sin embargo tu quieres asegurarte que los nombres en tu pagina web, la Inicial aparezca en Mayúscula. entonces es ahí donde ocupas el Transform para que la secuencia de entrada la puedas cambiar y produzca una secuencia de salida diferente.)


Bien que aquí prácticamente estas diciendo que sera en esta función será donde ejecutaras la transformación. al colocar Tranform.call(this) estas iniciando el llamado a la tranformacion de tu secuencia datos. y al colocar this estas diciendo que se hará dentro del método Mayus

function Mayus(){
    Transform.call(this);
}

dicho esto pasemos a lo siguiente…


bien acá por lo que busque y encontré.(porque el que busca encuentra) lo que hace util.inherits(Mayus,Transform); es crear una instancia de la clase Transform y estableciéndolo como prototipo a la función Mayus, tambien adjuntando el EventEmmitter. es decir el Transform.Call(this).
de modo que cada vez que se crea una instancia de la funcion Mayus se ejecutara el fichero.

en pocas palabras para el que sepa PHP o JAVA . es como llamar al metodo super()

util.inherits(Mayus,Transform);

CABE RECALCAR QUE NODE NO RECOMIENDA USAR ESTA FUNCIÓN


bueno bueno que tenemos acá.
pero miren justo Mayus.prototype._transform fue posible gracias a la función de util.inherits(Mayus,Transform) que establecía la clase Transform como prototipo de la función Mayus.

PERO QUE SIGNIFICA ._transform ?
bueno básicamente significa que la transformación que tu harás podrá ser personalizada, así es(como mi redacción). es decir que tu veras que cambio o que transformación le harás a la secuencia de datos que estas recibiendo como entrada.

Mayus.prototype._transform=function(chunk,codifi,callback){
     chunkMayus = chunk.toString().toUpperCase();
     this.push(chunkMayus);
     callback();
}

pasemos a lo siguiente…


bueno y por ultimo que sucede al final. pues simple
creas una instancia de la funcion Mayus

y bueno por ultimo lo que hace pipe() es limitar el almacenamiento en el buffer para que no haya una sobresaturacion a la hora se pasar la secuencia de los datos


var mayus = new Mayus();

readablesStream.pipe(mayus).pipe(process.stdout);

BUENO RECALCO QUE ESTO LO DESCRIBÍ CON MIS PROPIAS PALABRAS, si hay algo en lo que me equivoco al mencionar pues que comente para que así sepamos bien el error y entendamos bien el concepto

La clase no fue muy provechosa ya que hubo muchos conceptos que no se explicaron antes (ni tampoco en los cursos de Javascript) y que esta vez se usaron prácticamente sin explicación.

inherits
__transform
.pipe
.call

Me parece que se complicó demasiado para esta transformación, hizo muchas cosas rápidamente con explicaciones muy leves y no se entendió nada desde que empezó a hacer el Transform!

Saludos, creo que el profesor no entiende muy bien el codigo de la clase, es por eso que no explico muchas partes, creo que es posible simplificar el codigo para que sea mas entendible para todos los estudiantes y no tengan que preocuparse por cosas que no tienen que ver con streams como el prototipo, inherits y etc.

Hay una forma mas simple de escribir este transform:

const { Transform } = require("stream");
const { createReadStream } = require("fs");

const upperCaseTransform = new Transform({
  transform(chunk, encoding, callback) {
    this.push(chunk.toString().toUpperCase());
    callback();
  }
});

const readableStream = createReadStream(__dirname + "/example.txt");

readableStream.pipe(upperCaseTransform).pipe(process.stdout);

Les comparto un sandbox donde pueden verlo funcionando en vivo https://codesandbox.io/s/node-js-forked-5qiff?file=/src/index.js:0-373

Las Streams son colecciones de datos, como matrices o cadenas. La diferencia es que las transmisiones pueden no estar disponibles de una vez y no tienen que caber en la memoria. Esto hace que las transmisiones sean realmente poderosas cuando se trabaja con grandes cantidades de datos, o datos que provienen de una fuente externa o un fragmento a la vez.

const fs = require('fs');
const server = require('http').createServer();

server.on('request', (req, res) => {
  const src = fs.createReadStream('./big.file');
  src.pipe(res);
});

server.listen(8000);

Cuando un cliente solicita ese archivo grande, lo transmitimos un fragmento a la vez, lo que significa que no lo almacenamos en la memoria intermedia.

El error que tuvimos varios estaba en utilizar el this dentro de una arrow function. En ese caso la función apunta al objeto Window y no a Mayus.

Antes:

Mayus.prototype._transform = (chunk, codif, cb) => {
  chunkMayus = chunk.toString().toUpperCase();
  this.push(chunkMayus);
  cb();
}

Despues:

Mayus.prototype._transform = function (chunk, codif, cb) {
  chunkMayus = chunk.toString().toUpperCase();
  this.push(chunkMayus);
  cb();
}

En esta clase se usó funciones prototipal, he hecho un ejemplo usando las clases de es6 y quedo asi el buffer de transformacion.

/ BUFFER DE TRANSFORMACION
const Transform = stream.Transform;

function Mayus() {
  Transform.call(this)
}

util.inherits(Mayus, Transform);

Mayus.prototype._transform = function(chunk, codif, cb) {
  chunkMayus = chunk.toString().toUpperCase();
  this.push(chunkMayus)
  cb();
}

let mayus = new Mayus();

readableStream.pipe(mayus)
.pipe(process.stdout)

// Haciendolo con clase

class MayusC extends Transform {
  _transform(chunk, codif, cb){
    let chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus)
    cb();
  }
}

let mayusC = new MayusC();
readableStream.pipe(mayusC)
.pipe(process.stdout)

Solo es la parte de LEER
Dentro de poco subo la parte de escribir y la de hacer las dos cosas

Imagina que tienes un dulce enorme que transportar hacia tu casa para que tus hijos coman
Eres muy fuerte pero el dulce es demasiado grande, pero se te ocurre hacer algo traes una canasta y divides el dulce en partes llenas la canasta y envías esa canasta a tus hijos así tus hijos pueden ir comiendo los dulces que les enviaste mientras tus hijos se comen los dulces tú llenas la 2da canasta y la envías, así funciona esto

el búfer sería la canasta y streams sería el movimiento de enviar todo

Una vez sabiendo eso continuemos

Trabajaremos con archivos de texto en esta ocasión así que usaremos el módulo fs

const fs = require(‘fs’)

//Aquí estoy creando una variable que se llama readableStream
//Le decimos que habrá la dirección que indicamos y lea el input

let readableStream = fs.createReadStream(__dirname + ‘/input.txt’, ‘utf8’)

//Esto disparar un evento cada vez que recibamos datos y en el callback le decimos que queremos hacer con los datos
que van entrando
//(chuck) esto quiere decir una parte de lo que has recibido
//Podemos leer un archivo de 1GB y esperar que lea 1GB y luego nos muestre o
// Podemos decirle tráeme el chunk que ya tienes es decir si ya tienes 5mb tráelos que iré trabajando con eso

readableStream.on(‘data’, (chunk)=>{

console.log('new chunck recevid:')
console.log(chunk)

})

//Pero donde está la magia en todo esto ?
Pues verás te recomiendo que hagas el archivo input.txt y lo llenes de texto al azar 500 líneas de texto 100 lo que tú quieras

y veraz como cada vez que se llena el buffer (chunk) nos pasara al callaback donde le dijimos
okay muéstrame el avance del paquete que ya tienes de todo lo que tienes que mostrarme

Si te ayudo regale un like 😉
Te recuerdo que yo también estoy aprendiendo esto así que si tienes algo más que aportar estaría excelente

Streams


Un stream es el proceso de ir consumiendo datos al tiempo que se están recibiendo. En palabras del profesor, es el paso de datos entre un punto y otro.

const fs = require('fs')

let data = ''

let readableStream = fs.createReadStream(__dirname + '/input.txt')

readableStream.setEncoding('UTF8')
readableStream.on('data', chunk => data += chunk)

readableStream.on('end', () => console.log(data))

En estos casos podemos escribir en buffer de la salida del sistema, process.stdout es un buffer de escritura en que empieza a trabajar para generar todo esto.

process.stdout.write('hola')
process.stdout.write('que')
process.stdout.write('tal')

Para usar los streams, podemos usarlos de la siguiente forma

const Transform = stream.Transform

function Upper() {
    Transform.call(this)
}

util.inherits(Upper, Transform)

Upper.prototype._transform = function (chunk, codif, cb) {
    chunkUpper = chunk.toString().toUpperCase()

    this.push(chunkUpper)
    cb()
}

let upper = new Upper()

readableStream
    .pipe(upper)
    .pipe(process.stdout)

Tuve que ver diez veces el video a lo largo de una semana y por fin entendí todo jaja

Buffer es la forma en que podemos leer los datos es su forma mas sencilla, en este caso Node transmite estos datos Buffer en binario.
Poder convertir datos a Buffer nos ayudara a la velocidad y mejorar el rendimiento de la lectura y escritura de datos, debido que se hace en el lenguaje de más bajo nivel para las maquinas.
Los streams son puntos de lectura de Buffers, con estos podemos declarar que acciones ejecutar cuando se recibe un buffer. Existen tres tipos de streams, stream de lectura, de escritura y de lectura y escritura.
Un gran ejemplo de uso de los streams es el procesamiento de archivos grandes, como imágenes o videos, ya que podemos transformar estos a buffer y a través de los streams cargarlos o guardarlos parte por parte para mejorar el rendimiento de nuestro código.

Gracias a todos por los aportes, entendí mejor la clase después de leer todos los comentarios

Usando ES6 nos evitamos usar util.inherits y hace que sea un poco mas facil de entender

class Mayus extends stream.Transform{
  constructor(){
    super()
  }

  _transform(chunk, codif, cb){
    let chunkMayus = chunk.toString().toUpperCase()
    this.push(chunkMayus)
    cb()
  }
}
const fs = require('fs')
const stream = require('stream')
const util = require('util')

let data = '';
let readableStream = fs.createReadStream(__dirname+'/input.txt')
readableStream.setEncoding('UTF8')
readableStream.on('data',(texto)=> {
    data += texto

})

readableStream.on('end',() => {
    console.log(data)
})

// stream de escritura:
// process.stdout.write('hola')
// process.stdout.write('mundo')

const Transform = stream.Transform;
function Mayus(){
    Transform.call(this)
}
util.inherits(Mayus,Transform)

Mayus.prototype._transform = function(texto,codif,cb){
    textoMayuscula = texto.toString().toLowerCase()
    this.push(textoMayuscula)
    cb()
}
let mayus = new Mayus()
readableStream.pipe(mayus).pipe(process.stdout)

pipe():sirve para envío de datos y formas de envío

Sobre el uso de .pipe estuve investigando un poco y encontre lo siguiente que creo les puede servir de ayuda para el uso del mismo.

por ejemplo si tienen una función, donde getName es transformado a mayusculas, luego se seleccionan los prieros 6 caracteres y luego se escribe en reverso como la siguiente, se vuelve un poco complicado de leer:

reverse(get6Characters(uppercase(getName({ name: 'Buckethead' }))));
// 'TEKCUB'

el uso de .pipe lo facilita de la siguiente manera:

pipe(
  getName,
  uppercase,
  get6Characters,
  reverse
)({ name: 'Buckethead' });
// 'TEKCUB'

Es algo que de un articulo de internet y me parecio valioso compartirlo aqui pueden leer el articulo

La documentación de Util dice que es mejor usar las keywords de ES6 class y extends, ya que no habrá compatibilidad a futuro, les comparto mi solución usando esta sintaxis:

const Transform = stream.Transform

class Mayus extends Transform{
    _transform(chunk, encoding, callback) {
        const chunkMayus = chunk.toString().toUpperCase()
        this.push(chunkMayus)
        callback()
    }
}

const mayus = new Mayus()

readStream.pipe(mayus).pipe(process.stdout)

Hola, hasta ahora excelente el curso. De este video me queda la duda de porque hay que hacer tantos trucos para usar el Stream de transformación? No parece natural. Gracias.

util.inherits está descontinuado. Pero se puede sustituir por la keyword class, de esta forma:

const Transform = stream.Transform;

class Mayus extends Transform {
    _transform(chunk, codif, cb) {
        let chunkMayus = chunk.toString().toUpperCase();
        this.push(chunkMayus);
        cb();
    }
}

let mayus = new Mayus();

readatableStream
    .pipe(mayus)
    .pipe(process.stdout)

Este código:

const Mayus = function(){
    stream.Transform.call(this);
}
util.inherits(Mayus, stream.Transform);
Mayus.prototype._transform = function(chunk, codif, cb){
    const chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    cb();
}

Es equivalente a

const Mayus = function(){
    stream.Transform.call(this);
};
Mayus.prototype = Object.create(stream.Transform.prototype);
Mayus.prototype.constructor = Mayus;
Mayus.prototype._transform = function(chunk, codif, cb){
    const chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    cb();
}

Y equivalente a

class Mayus extends stream.Transform{
    constructor(props) {
        super(props);
    }
    _transform(chunk, codif, cb){
        const chunkMayus = chunk.toString().toUpperCase();
        this.push(chunkMayus);
        cb();
    }
}

Quisiera aportar el siguiente código usando el class de Javascript:

// ....
const Transform = stream.Transform;

class Mayus extends Transform {
      constructor() {
            super();
            Transform.call(this);
      }
      _transform = (chunk, codif, cb) => {
            let chunkMayus = chunk.toString().toUpperCase();
            this.push(chunkMayus);
            cb();
      };
}

// ...

A mí me sirvió para resolver un error que saltó en mi consola al intentar usar la versión de esta clase.

🙂 Saludos y muchos éxitos, colegas!

SI no les quedo claro, talvez con las sintaxis de ES6 se entienda mejor, de igual forma pueden leer la documentación aquí

class Mayus extends Transform {
  _transform(chunk, codif, cb) {
    let chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    cb();
  }
}

const mayus = new Mayus();
readableStream.pipe(mayus).pipe(process.stdout);

¯\_(ツ)_/¯

En mi última aplicación tuve que desarrollar la subida de archivos de tipo pdf pero en general funciona para cualquier tipo de archivos.
En ese caso que les platico, realicé la funcionalidad con módulos de Stream.
Ustedes, ya de ante mano, realizaron sus configuraciones de Express para el desarrollo API de un backend web.

En nuestras primeras líneas, observarán una “configuración” típica de un fs para obtenera la información de recurso fs.createReadStream
En ello, se establece una comunicación con el Backen, a través de un endpoint de servicio, para obtener todo ese blob de información.
En mi caso, subí la información a FireStore para su almacenamiento.

Encontrarán el caso donde se limpía el nombrado del archivo para evitar acentos o guiones bajos y dejarlo límpio en un solo formato.
Ambos puntos, establecen la comunicación para que, cuando terminen, ambos se mencionen:

  1. Desde el cliente, ya no tengo más que subir.
  2. Desde el backend, ok (200) ya tengo todo arriba.

Este es el código del profe con unas cuantas notas explicando lo que hace cada cosa.
utilicé aportes de los compañeros en los comentarios para entenderlo un poco mejor y aca les dejo mis apuntes por si a alguien le sirve

const fs = require('fs');
const stream = require('stream');
const util = require('util');

let data = '';

//createReadStream me permite generar un stream de lectura
//en este casoestoy tomando un archivo de texto cualquiera como input
let readableStream = fs.createReadStream(__dirname + '/input.txt');

// readableStream irá recibiendo los paquetes o chunks en formato de buffer 
// y en este caso los estoy parceando a utf8
// chunk es como se llama a cada paquete o fragmento de datos que iré leyendo
readableStream.setEncoding('UTF8');

//   readableStream.on('data'...) inicia una escucha de evento en la que escucharé
//   cuando reciba la información del archivo a leer
//   luego iré añadiendo los chunks a mi variable data declarada previamente
// readableStream.on('data', function (chunk) {
//     data += chunk;
// });

//   readableStream.on('end'...) escucha a cuando se termina de recibir datos del archivo
//   de texto. en ese momento hago un consol.log y muestro el total de la data
// readableStream.on('end', function() {
//     console.log(data);
// });

//   Aquí estoy escribiendo en el buffer de la salida del sistema
//   es el ejemplo mas sencillo de stream de escritura
// process.stdout.write('hola')
// process.stdout.write('que')
// process.stdout.write('tal')

// Ya vimos stream de lectura y de escritura ahora veremos la forma media en la que
// leemos la secuencia la transformamos y volvemos a escribir

// lo que se hace aquí es crear una constante que va a contener la clase Transform,
// pero… que es lo que hace Transform?.
// transforma la secuencia de entrada para que la secuencia de salida sea una diferente.
const Transform = stream.Transform;

// en esta función será donde ejecutaras la transformación. al colocar Tranform.call(this)
// estas iniciando el llamado a la tranformacion de tu secuencia datos
// y al colocar this estas diciendo que se hará dentro del método Mayus
function Mayus() {
    Transform.call(this);
}

// util.inherits(Mayus,Transform); es crear una instancia de la clase Transform 
// y estableciéndolo como prototipo a la función Mayus, tambien adjuntando el EventEmmitter.
// es decir el Transform.Call(this).
// de modo que cada vez que se crea una instancia de la funcion Mayus se ejecutara el fichero.
// en pocas palabras para el que sepa PHP o JAVA . es como llamar al metodo super()
util.inherits(Mayus, Transform);

// le agrego una funcion personalizada a mayus (paquete, codificacion, callback)
Mayus.prototype._transform = function(chunk, codif, cb) {
    chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    cb();
}

// aqui es donde comienzo a hacer la trnasformacion, lo anterior era 
// la configuracion o codigo necesario
let mayus = new Mayus();

readableStream // entrada
    .pipe(mayus) // transformacion
    .pipe(process.stdout); //salida

    // pipe() limita el almacenamiento en el buffer para que no haya una 
    // sobresaturacion a la hora se pasar la secuencia de los datos

Qué clase más compleja!, pero estuvo rebuena!. Tuve que usar un archivo muy grande para ver con mis propios ojos el tema de los chunks! 😄

Noté entonces que cada chunk era de aproximadamente 64kb, y ahí ya empecé a entender mejor el procedimiento.

Está super el curso!

La implementación de ejemplo de los stream de transformación es algo engorrosa, ya que podíamos hacer lo mismo en el readableStream con un .toUpperCase() en el evento ‘data’, antes de concatenar el chunk a la variable data.

<h1>Streams<h1>

son colecciones de datos, como matrices o cadenas. La diferencia es que las transmisiones pueden no estar disponibles de una vez y no tienen que caber en la memoria. Esto hace que las transmisiones sean realmente poderosas cuando se trabaja con grandes cantidades de datos, o datos que provienen de una fuente externa o un fragmento a la vez.

<h4>Streams de lectura</h4>
const fs = require('fs');
let data = ""
let stream = fs.createReadStream (__dirname + "./archivo.txt") // importamos un archivo
stream.on("data", (chunk) => {
	console.log(chunk) // veremos el chunk que recibimos
// si son varios chunk usamos data += chunk
// podemos usar stream.setEncoding(UTF8) para convertir a sting
});
// para imprimir una vez terminado
stream.on("exit", (chunk) => {
	console.log(data)
}); // cuidado con las arrow function aquí porque this puede señala a windows
<h4>Streams de escritura</h4>
process.stdout.write("hola")
process.stdout.write("que")
process.stdout.write("tal")
// OUTPUT: holaquetal
// stdout ya es un buffer de escritura
<h4>Streams de lectura y escritura (transformación)</h4>
const stream = requiere("stream")
const transform = string.tranform // esto crea un string de tranformación 
cont util = require("util")

function mayusculator () {
	transform.call(this)
}
util.inherts(mayusculato, transform);
mayusculator.prototye.transorm = function (chunk, codif, callback) {
	chunkmayusculator = chunk.toString().tuUpperCase();
	this.push(chunkmayusculator)
callback()
}
let mayus = new mayus ()
	stream.pipe(mayus)
				.pipe(process.stdout)

La verdad no endí la ultima, solo lo copiaré quiza no entienda ahora pero mas adelante cuando aprenda nuevos conceptos sí, igualmente hay otros cursos con otros profesores que explican el mismo concepto, quizá a ellos si le puedan entender no se romapn la cabeza 😃

No entendí el motivo de utilizar 'util.inherits', cuando se podría usar simplemente Mayus.prototype = new Transform() ``` const fs = require('fs'), stream = require('stream') const const readable = fs.createReadStream(__dirname + '/texto.txt') const Transform = stream.Transform function Mayus(_this) { Transform.call(this) } Mayus.prototype = new Transform() Mayus.prototype._transform = function(chunk, codif, cb) { mayusChunk = chunk.toString().toUpperCase() this.push(mayusChunk) cb() } const mayus = new Mayus(this) readable.pipe(mayus).pipe(process.stdout) ```

Streams
Los streams son flujos de información que usamos en la transmición de datos binarios. El flujo de información que forma un stream se transmite en pedazos, mejor conocidos como chunk. Los chunk no son más que objetos de la clase Buffer

Esta clase es importantísima. Se me ocurre que podemos desarrollar filtros para audio, video, overlays de caracteres para transmisiones en vivo, codecs y más. Habrá que probar. Gracias!

Si quieren verlo en forma de clases en lugar de prototipos creo que se entiende mejor:

const fs = require('fs')
const {Transform} = require('stream')

let readableStream = fs.createReadStream(`${__dirname}/input.txt`)
readableStream.setEncoding('UTF8')

/*al colocar Tranform.call(this) estas iniciando el llamado a la tranformacion de tu secuencia datos. y al colocar this estas diciendo que se hará dentro de la clase (tomado de otro comentario)*/

class UpperCase extends Transform {
    constructor(){
        super()
        Transform.call(this)
    }

    _transform(chunk, encoding, cb) {
        let upperChunk = chunk.toString().toUpperCase()
        this.push(upperChunk)
        cb()
    }
}

//se crea la instancia de la clase
let upperCase = new UpperCase()

readableStream
    .pipe(upperCase)
    .pipe(process.stdout)

Por si se confudieron como yo al ver “util.inherits”, “_transform”
, “.call” . Y todo la implantación rara (al menos para mi), acá les dejo mi versión usando Clases ES6:

Lo que hacemos es crear una nueva clase “Mayus” que hederá de “Transform” que proviene del modulo “stream”, si no recuerdan para que sirven la funcion super dentro del constructor es para que la clase "Mayus " hederé todas las propiedades del objeto “Transform”, pero en “Mayus” cambiamos el comportamiento del metodo _transform, el cual es la funcion que va a transformar el contenido del stream por medio de una pipe. Siendo lo mas raro dentro de esta funcion el “this.push()” lo cual no es nada mas la forma de devolver una salida legible para los streams (o eso entendi de la documentacion). Aca les dejo parte de la documentacion oficial por si se perdieron con mi explicacion:


“All Transform stream implementations must provide a _transform() method to accept input and produce output. The transform._transform() implementation handles the bytes being written, computes an output, then passes that output off to the readable portion using the transform.push() method.”

Stream

Se refiere al paso de datos entre 2 puntos. Existen varios tipos de stream:

  • Stream de lectura: Es donde existe un origen y el stream se encarga de traer datos y podemos gestionarlos como deseemos.
  • Stream de escritura: Es donde tengo datos y mediante el stream mando datos a un destino concreto.
  • Stream de doble sentido (lectura y escritura): Cumple la función de los dos anteriores.

Stream de lectura

Para crear un stream que sea legible, se debe importar el módulo fs .

const { createReadStream } = require('fs')

Luego de esto, se debe crear obtener los datos o el archivo que contiene el buffer que se debe stremear.

let readableStream = createReadStream(`${__dirname}/input.txt`)

Se puede configurar la codificación del archivo, para no tener que acudir a métodos como toString() , sino que sea algo más orgánico.

readableStream.setEncoding('utf-8')

Utilizando los métodos del stream, se debe escuchar el evento 'data' que permite saber cuando llega nueva información, en este caso se hace una función que mande por consola lo que es obtenido de la 'data' .

readableStream.on('data', (chunk) => {
  console.log(chunk)
})

Para obtener archivos grandes de información la siguiente forma es la más adecuada para ir recibiendo los chunks y luego manejarlos.

  1. Se crea una variable que va a ir recibiendo los datos:

    let data = ''
    
  2. En la función se guarda la información que se obtiene en la variable data .

    readableStream.on('data', (chunk) => {
      data += chunk
    })
    
  3. Para saber cuando se termina de recibir la información, se hace lo siguiente.

    readableStream.on('end', () => {
      console.log(data)
    })
    

    Esto sirve cuando se trabaja con archivos muy grandes de información.

Stream de escritura

Mediante la salida estándar del sistema stdout se puede generar un buffer de escritura, pero no tiene estructura por si mismo.

process.stdout.write('Hola')
process.stdout.write('que')
process.stdout.write('tal')

/*
Output:
Holaquetal
*/

Buffer de transformación

Se debe importar el módulo stream .

const stream = require('stream')

En este caso se va a convertir un buffer de datos a mayúsculas.

  1. Se debe crear un stream de transformación mediante una clase que va a heredar de stream.Transform , esto se hace utilizando la sintaxis de EcmaScript6.

    class Mayus extends stream.Transform {
    	_transform(chunk,encode,cb) {
    		let chunkMayus = chunk.toString().toUpperCase()
    		this.push(chunkMayus)
    		cb()
    	}
    }
    
    /*
    Output:
    ESTE 
    ES 
    UN 
    ARCHIVO
    QUE 
    VAMOS 
    A 
    LEER
    */
    

stdout: ya es un buffer de escritura

require(‘util’): permite trabajar con herencia automatico

Creo que muchos entendemos que aquí hubo herencia prototipal y demás cosas, lo confuso aquí son los métodos que se utilizaron, ya que según veo son propios de los módulos que se están requiriendo.

Considero que para entender mejor esta clase se tuvo que haber explicado al menos por encima los metodos que se usaron, tanto los de stream como los de util.

Es INCREIBLE lo bien que funciona el uncaughtException, tuve algunos errores en mi escritura de codigo, por lo tanto utilice este process con un console.error(err.message), 2 segundos mas tardes ya habia limpiado todo.
Sin lugar a dudas es increible la documentacion que nos prepara platzi para entender y mejorar!

Se puede pasar el codigo de la parte final a ECMAscript 2015 y quedaria asi.

const  { createReadStream } = require('fs')
const stream = require('stream')
let readableStream = createReadStream(__dirname + '/input.txt')

class Mayus extends stream.Transform {
    _transform(chunk, codif, cb) {
        let chunkMayus = chunk.toString().toUpperCase();
        this.push(chunkMayus);
        cb();
    }
}
let mayus = new Mayus();

readableStream
    .pipe(mayus)
    .pipe(process.stdout)

Wooow esta clase si me ha volado la cabeza, no la entendí 😦

hace mucho que a una clase no le entendia jajajajaj

Que horrible clase, me imagino que el tema es complejo pero aun asi falto mucha explicación , parece una clase de magia porque todo apareció de la nada

Una consulta, veo un curso de Fundamentos, luego un Curso de Node y luego un curso Práctico, dados por el gran Carlos. El orden sería tal cual los he citado, ¿verdad?

Lo mismo tampoco estaría mal actualizarlos para ya usar clases y todo lo que trae ES6+

Un saludo y gracias.

PD: Gracias también a los compañeros como siempre por compartir.

Para los que se confundieron:

Básicamente necesitamos crearnos una ++clase ++que herede el funcionamiento de Tranform

(para los que saben java este concepto está más fácil)

Por lo cual

podemos borrar:

function Mayus() {
    Transform.call(this);
}
util.inherits(Mayus, Transform);

cambiarlo por :

class Mayus extends Transform {
}

esto sugieren los IDE, donde hacen mención a Ecmascript 6.

todo lo que eliminamos básicamente era un truco para que Mayus herede el Transform ()

El codigo me da error.

const fs = require('fs');
const stream = require('stream');
const util = require ('util');

 let data = '';

 let readableStream = fs.createReadStream(__dirname + '/input.txt');
 readableStream.setEncoding('UTF8');

const Transform = stream.Transform;

function Mayusculas() {
    Transform.call(this);
}

util.inherits(Mayusculas, Transform);

Mayusculas.prototype._transform = (chunk, codif, callback) => {
    chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    callback();
}

let mayus = new Mayusculas();

readableStream
    .pipe(mayus)
    .pipe(process.stdout);

El mensaje de error que arroja es este:

$ node stream.js
C:\Users\fgarcia\Platzi\FundamentosNodeJS\memoria\stream.js:36
    this.push(chunkMayus);
         ^

TypeError: this.push is not a function
    at Mayusculas._transform (C:\Users\fgarcia\Platzi\FundamentosNodeJS\memoria\stream.js:36:10)
    at Mayusculas.Transform._read (_stream_transform.js:189:10)
    at Mayusculas.Transform._write (_stream_transform.js:177:12)
    at doWrite (_stream_writable.js:435:12)
    at writeOrBuffer (_stream_writable.js:419:5)
    at Mayusculas.Writable.write (_stream_writable.js:309:11)
    at ReadStream.ondata (_stream_readable.js:728:22)
    at ReadStream.emit (events.js:223:5)
    at addChunk (_stream_readable.js:309:12)
    at readableAddChunk (_stream_readable.js:286:13)

Lo que hace es literalmente leer input.txt, despuésmodifica ese buffer la función Mayus y finalmente lo imprime al stdout.
.
Para pasar datos de un lado a otro de usa la función pipe() 😁
.
Aún así no me queda claro si todo esto se hace en un sólo stream, alguien podría decirme si sí es un solo stream?

Este video puede ser confuso ya que en JavaScript no se manejan clases, es cierto que se usa

new Mayus()

Pero en realidad es Syntactic Sugar, al final, todo en JavaScript son Prototipos y me parece que hay un curso de JavaScript aquí en Platzi en el cual explican mejor todos estos conceptos y como this se comporta diferente si se utilizan Arrow Functions.

el tranform llevándolo a un contexto real me imagino que puede servir para cambiar la definición de un vídeo o no?

Algo no hice bien, pero no se donde!

me da este error!

nodemon] clean exit - waiting for changes before restart
[nodemon] restarting due to changes...
[nodemon] starting `node stream.js`
HOLA 
EVENTSOURCE
ES UN 
ARCHIVO 
        XMLDOCUMENT

        X_0
/Applications/XAMPP/xamppfiles/htdocs/platzi master/Fundamentos de nodeJS/memoria/stream.js:24
    this.push(chunkMayus);
         ^

TypeError: this.push is not a function
    at Mayus._transform (/Applications/XAMPP/xamppfiles/htdocs/platzi master/Fundamentos de nodeJS/memoria/stream.js:24:10)
    at Mayus.Transform._read (_stream_transform.js:189:10)
    at Mayus.Transform._write (_stream_transform.js:177:12)
    at doWrite (_stream_writable.js:431:12)
    at writeOrBuffer (_stream_writable.js:415:5)
    at Mayus.Writable.write (_stream_writable.js:305:11)
    at ReadStream.ondata (_stream_readable.js:726:22)
    at ReadStream.emit (events.js:210:5)
    at addChunk (_stream_readable.js:308:12)
    at readableAddChunk (_stream_readable.js:285:13)
[nodemon] app crashed - waiting for file changes before starting...```

No se si entienda un poquito mejor la utlima parte usando clases, aquí dejo el código como lo entendí.
Transform lo me que permite es alterar alterar los datos que pasan por el stream (flujo de datos). Como en este caso pasar a mayusculas el recurre al metodo _transform para operar con los datos, el cual lo definimos para darle la funcionalidad que nosotros deseamos.

class Mayus extends Transform{
    constructor(){
        super()
        Transform.call(this);
    }
    _transform(chunk,codif,cb){
        let chunkMayus = chunk.toString().toUpperCase();
        this.push(chunkMayus);
        cb();
    }
}

me esta dando error.

Este es mi codigo

const fs = require('fs');
const stream = require('stream');
const util = require ('util');

 let data = '';

 let readableStream = fs.createReadStream(__dirname + '/input.txt');
 readableStream.setEncoding('UTF8');




const Transform = stream.Transform;

function Mayusculas() {
    Transform.call(this);
}

util.inherits(Mayusculas, Transform);

Mayusculas.prototype._transform = (chunk, codif, callback) => {
    chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    callback();
}

let mayus = new Mayusculas();

readableStream
    .pipe(mayus)
    .pipe(process.stdout);


el error que me da es este:

$ node stream.js
C:\Users\fgarcia\Platzi\FundamentosNodeJS\memoria\stream.js:36
    this.push(chunkMayus);
         ^

TypeError: this.push is not a function
    at Mayusculas._transform (C:\Users\fgarcia\Platzi\FundamentosNodeJS\memoria\stream.js:36:10)
    at Mayusculas.Transform._read (_stream_transform.js:189:10)
    at Mayusculas.Transform._write (_stream_transform.js:177:12)
    at doWrite (_stream_writable.js:435:12)
    at writeOrBuffer (_stream_writable.js:419:5)
    at Mayusculas.Writable.write (_stream_writable.js:309:11)
    at ReadStream.ondata (_stream_readable.js:728:22)
    at ReadStream.emit (events.js:223:5)
    at addChunk (_stream_readable.js:309:12)
    at readableAddChunk (_stream_readable.js:286:13)

Es la primera clase de Carlos que no me quedó claro a la primeria. pero razoné que lo que estaba haciendo era crear una clase Mayus que extiende a Transform y que sobrecarga el método _transform.

aquí mi versión con alta azúcar sintáctica.

class Mayus extends stream.Transform{
    _transform(chunk, codif, cb){
        const chunkMayus = chunk.toString().toUpperCase();
        this.push(chunkMayus);
        cb();
    }
}

let mayusc = new Mayus();

readableStream.pipe(mayusc).pipe(process.stdout);

Para los que de pronto no entendieron bien el comportamiento de _transform o inherits, aquí les dejo el mismo código escrito de otra manera para ver si lo pueden entender mejor!

const fs = require('fs');
const stream = require('stream');

let data = ''; 

let readeableStream = fs.createReadStream(`${__dirname}/practicas.js`);

readeableStream.setEncoding('UTF8');

readeableStream.on('data', datos => {
    data += datos; 
}) 

readeableStream.on('end', () => {
    console.log('Ya se termino!!!')
});

class Mayus extends stream.Transform { // Ingresa CTRL + Click en el stream.Transform para ver que en el constructor se ejecuta el método que estamos sobrescribiendo (VS Code)
    _transform(chunk) { // Y este es el método que apenas se ejecuta con el constructor
        let chunkMayus = chunk.toString().toUpperCase();
        console.log(this);
        this.push(chunkMayus);
        console.log(this);
    }
}
// El pipe básicamente es un concepto que también se ve en la consola que es pasarle información de un comando a otro para que lo utilice de argumento, si no te quedo muy claro googlea 'Pipe operators' y de pronto vas a comprenderlo mejor
readeableStream 
    .pipe(new Mayus()) // Vas a ver que el pipe va a pasarle lo que leyó como opciones del constructor!
    .pipe(process.stdout)

Les comparto esto que puede resultar una gran herramienta a lo hora de tratar de entender este tipo de cosas que a veces los profes se salta.

Si mantienen presionado la tecla Ctrl. y posicionan su cursor sobre las clases, métodos, objetos y demás en VSCode, te brinda más información sobre el mismo, por ejemplo su construcción o instanciación e incluso se subraya y vuelve hipervínculo que te lleva al Código del mismo

Al hacer esto, sobre el ‘stream’ de const Transform = stream.Transform; pude ver que stream es una clase y que Transform viene igual de otra clase.

Cuando hacer esto, y navegas por el Código, encuentras lo siguiente que ayuda a entender mejor el Transform y el _transform.

Aquí abajo el código de cada una por si les ayuda a entender mejor.

class Transform extends Duplex {
            constructor(opts?: TransformOptions);
            _transform(chunk: any, encoding: BufferEncoding, callback: TransformCallback): void;
            _flush(callback: TransformCallback): void;
        }

Con esto pude entender que no estamos nombrando cosas al aire sino más bien invocando clases o prototipos del internal de Node.

Si aportar más a esto, estaría de lujo ya que siento que si quedó poco claro.

Les dejo el código por si alguien se perdió sobre el final como yo 😁

const fs = require("fs");
const stream = require("stream");
const util = require("util");

let data = "";

let readableStream = fs.createReadStream(__dirname + "/input.txt")

readableStream.setEncoding("utf-8");

// readableStream.on("data", function (chunk) {
// 	console.log(chunk);
// });

// readableStream.on("end", function() {
// 	console.log(data);
// });

// process.stdout.write("Hola");
// process.stdout.write("que");
// process.stdout.write("tal");

const Transform = stream.Transform;

function Mayus() {
	Transform.call(this);
}

util.inherits(Mayus, Transform);

Mayus.prototype._transform = function(chunk, codif, cb) {
	chunkMayus = chunk.toString().toUpperCase();
	this.push(chunkMayus);
	cb();
}

let mayus = new Mayus();

readableStream
	.pipe(mayus)
	.pipe(process.stdout) 
/* Streams es el paso de datos de un lado a otro */

const fs = require('fs');
const stream = require('stream');
const util = require('util');

let data = '';
/* 
Con esto empezamos a abrir los datos de un archivo */

let reasableStream = fs.createReadStream(__dirname + '/input.txt');

/* reasableStream.on('data', function (chunk) {
    console.log(chunk);
    console.log(chunk.toString());
}) */
/* Esta es una forma de pasar la informacion de hexa a formato UFT8 */
reasableStream.setEncoding('UTF8');

/* Si tenemos un archivo muy pero muy grande podemos enviar toda la informacion a que se procese primero y cuando este todo listo mostralo, se hace asi: */

/* reasableStream.on('data', function (chunk) {
   data += chunk;
})

reasableStream.on('end', function () {
    console.log(data);
    console.log('Soy yo');
 }) */

/* la diferencia de hacer esto se nota en memoria y para cosas grandes como suvir  un archivo de 20GB  a internet */

/* Esto es un steam de escritura */

/* process.stdout.write('Hola')
process.stdout.write('que')
process.stdout.write('tal') */


/* Esto es un buffer de lectura y escritura lee del fichero pasa a mayuscula y escribe */

const Transform = stream.Transform;

function Mayus() {
    Transform.call(this);
}
util.inherits(Mayus, Transform);

Mayus.prototype._transform = function(chunk, codif, cb) {
    chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    cb();
}

let mayus = new Mayus();

reasableStream
    .pipe(mayus)
    .pipe(process.stdout);

Un chunk es un conjunto de buffers? O es lo mismo?

que es chunk?

Aqui esta la documentacion de node sobre Transform y algunas alternativas de como es posible escribirlos https://nodejs.org/docs/latest/api/stream.html#stream_implementing_a_transform_stream

Intente hacer el ejecicio con ARROW FUNCTIONS:

 () => {}

No pude por que marcaba error. Que raro.

Aquí les dejo una lectura sobre los Streams en NodeJS

Para cosas muy pequeñas no tiene sentido utilizar un stream, pero tú lo haz hecho en el ejemplo. Hubiese sido útil con un ejemplo apropiado al caso. Los ejemplos deben servir para ilustrar y aclarar un tema, no dar un mal ejemplo y decir “esto no tiene sentido, se usa para otra cosa”, se entiende? Para la próxima clase quizás, o si te agrade hacerte cargo y regrabar esta. Gracias.

Mala la clase

Me explotó la cafetera con esta clase jajaja

La clase fue muy didactica

Esta tema no es sencillo. Podría dar para un curso entero.

Alguien sabe que sig que algo empiece con mayuculas? Por ejemplo Transform

La verdad de esta clase solo entendí hasta que hizo la modificación de ahí para adelante se fue enredando como un callback hell xD

quien seria this en este caso??

Podría decirse que un Stream es el proceso de ir consumiendo datos al tiempo en que se reciben

Me perdí y hasta me saco error jajajajaja íbamos bien pero aquí varios conceptos estuvieron bastantes complejos.

Me surge la duda, ¿se podría utilizar class de ES6 para este caso?

Estaría muy bueno que añadan un video luego de este donde se nos proporcione en archivos un file extensivo y mandarlo a una variable en chunks para notar esa diferencia.

En qué caso usar streams

Streams pasar algo de un lugar a otro

A mi me imprime directo en UTF-8 sin que lo especifique o lo cambie a string 😮 Alguien sabe pq? Tal vez nueva versión

💥

Desde el minuto 08:10 no entendí lo que pasaba, jajaj

Entendí poco la última parte 😦

Ahora sé por qué mientras mis podcasts cargan dicen: Almacenando en búfer. Ahí me viene una pregunta: ¿Cómo se trata ésto con archivos de audio y video?

<h3>Streams</h3>

son colecciones de datos, como matrices o cadenas. La diferencia es que las transmisiones pueden no estar disponibles de una vez y no tienen que caber en la memoria. Esto hace que las transmisiones sean realmente poderosas cuando se trabaja con grandes cantidades de datos, o datos que provienen de una fuente externa o un fragmento a la vez.

<h4>Streams de lectura</h4>
const fs = require('fs');
let data = ""
let stream = fs.createReadStream (__dirname + "./archivo.txt") // importamos un archivo
stream.on("data", (chunk) => {
	console.log(chunk) // veremos el chunk que recibimos
// si son varios chunk usamos data += chunk
// podemos usar stream.setEncoding(UTF8) para convertir a sting
});
// para imprimir una vez terminado
stream.on("exit", (chunk) => {
	console.log(data)
}); // cuidado con las arrow function aquí porque this puede señala a windows

podemos pasar imagenes o videos en streams y usando butter para transmitirlos de un lado a otro y luego procesarlos para tener la imagen

Siempre que necesito volver a entender streams, leo este post

https://medium.com/edge-coders/node-js-streams-everything-you-need-to-know-c9141306be93

Bueno aquí el profe fue un poco rápido, supongo que es por que es un tema que se debe profundizar y en otros cursos se vera mas a profundidad

Excelente clase.

// Import
const fs = require('fs')
const stream = require('stream');
const util = require('util');

// Words on the file
let data = '';

// Input stream
let readableStream = fs.createReadStream(__dirname + '/input.txt');

// Encoding of the info
readableStream.setEncoding('UTF8');

// When getting the chunks of data
/* readableStream.on('data', (chunk) => {
    //console.log(chunk);
    data += chunk;
})

// Print after finish reading
readableStream.on('end', () => {
    console.log(data);
}) */

/* process.stdout.write('hola')
process.stdout.write('que')
process.stdout.write('tal')
 */

const Transform = stream.Transform;

function Mayus() {
    Transform.call(this);
}

// Mayus traer todo lo que neceista de transform
util.inherits(Mayus, Transform);

Mayus.prototype._transform = function(chunk, codif, cb) {
    chunkMayus = chunk.toString().toUpperCase();
    this.push(chunkMayus);
    cb();
}

var mayus = new Mayus();
readableStream
    .pipe(mayus)
    .pipe(process.stdout);