#¿Qué hay de nuevo en io.js 1.0 Beta? - Streams 3
Los streams de Node son una forma poderosa de construir módulos y aplicaciones que manejan grandes streams de data. La API de Streams ha pasado por varias revisiones y ha estado mejorando establemente. Los Streams 1 introducieron push-streams para permitir a los desarrolladores consumir data eficientemente. Los Streams 2 agregaron pull-streams en adición a push-streams para permitir casos de uso más avanzados, sin embargo, los dos estilos no pueden utilizarse juntos. Los Streams 3 resuelven este problema de una manera elegante y permite al mismo stream ser utilizado tanto en modo push cómo en modo pull. Los Streams 3 están disponibles en Node v0.11/v0.12 y io.js
Continua leyendo para entrar en los detalles.
En la implementación original de streams un evento de data era generado todas las veces que la data estaba disponible en el stream.
Los desarrolladores podían usar pause()
y resume()
para controlar el flujo. Llamando pause()
causaría que la implementación dejara de mandar eventos de data.
// node 0.8
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
// Resume the stream in 1 second
setTimeout(stream.resume.bind(stream), 1000);
var data = '';
stream.on('data', function(chunk) {
data += chunk;
})
stream.on('end', function() {
// End of the stream has been reached and no more data can be read
console.log('Data length: %d', data.length);
});
> node test.js
Data length: 1506
Sin embargo, los Streams 1 tenían algunos problemas que Isaac mencionó en Diciembre del 2012:
- El elemento
pause()
no pausaba. - Los eventos
data
llegaban enseguida (ya sea si estabas listo o no) - No había forma de consumir un específico número de bytes, y después dejar el resto para que lo maneje otra parte del programa.
Node 0.10 introdució la API de Streams 2 la cual agregó un modo pull para leer data del stream de manera de poder evitar los problemas mencionados anteriormente. Los streams siempre empezarían en el estado pausado y la data podría leerse usando el método read(numBytes)
. En adición, un evento "readable" sería emitido cuando la data esté disponible
// node 0.10 - pull stream, readable event example
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
// No need to pause the stream
// stream.pause();
var data = '';
stream.on('readable', function() {
var chunk;
while(chunk = stream.read()) {
data += chunk;
}
});
stream.on('end', function() {
// End of the stream has been reached and no more data can be read
console.log('Data length: %d', data.length);
});
> node test.js
Data length: 1506
El modo push original de Streams 1 de leer la data todavía estaba disponible y podría ser usado agregando un handler al evento data. Agregar el handler del evento data tenía el efecto secundario de reanudar el stream
// node 0.10 - push stream, data event example
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
// Resume the stream in 1 second
setTimeout(stream.resume.bind(stream), 1000);
var data = '';
stream.on('data', function(chunk) {
data += chunk;
})
stream.on('end', function() {
// End of the stream has been reached and no more data can be read
console.log('Data length: %d', data.length);
});
> node test.js
Data length: 1506
Sin embargo, los modos pull y push no podían utilizarse juntos.
// node 0.10 - Non-working mixing example
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
var pulledData = '';
var pushedData = '';
stream.on('readable', function() {
var chunk;
while(chunk = stream.read()) {
pulledData += chunk;
}
});
stream.on('data', function(chunk) {
pushedData += chunk;
});
stream.on('end', function() {
// End of the stream has been reached and no more data can be read
console.log('Pulled data length: %d', pulledData.length);
console.log('Pushed data length: %d', pushedData.length);
});
> node test.js
Pulled data length: 1506
Pushed data length: 0
No sería mejor si esto fuera posible? Haría que el debugging o agregar un handler para logging sea mucho más fácil si pudieras agregar lo siguiente a un stream en modo pull.
stream.pause();
stream.on('readable', function() { ... });
// Debug logging
stream.on('data', function(data) { console.log(data) });
Con io.js v1.0.1, tenemos una nueva implementación de streams que te permite mezclar y usar ambos enfoques. Por default, los
streams todavía estarán pausados, y agregando el handler al evento data todavía reanudará el stream. Sin embargo, si pausamos el stream y llamamos el método read()
, emitirá un evento data correspondiente.
// node 0.11+, io.js 1.0.1
var fs = require('fs');
var stream = fs.createReadStream('readme.txt');
stream.setEncoding('utf8');
stream.pause();
var pulledData = '';
var pushedData = '';
stream.on('readable', function() {
var chunk;
while(chunk = stream.read()) {
pulledData += chunk;
}
});
stream.on('data', function(chunk) {
pushedData += chunk;
});
stream.on('end', function() {
// End of the stream has been reached and no more data can be read
console.log('Pulled data length: %d', pulledData.length);
console.log('Pushed data length: %d', pushedData.length);
});
> node test.js
Pulled data length: 1506
Pushed data length: 1506