stringdecoder - Node.js: ¿Cómo leer una secuencia en un búfer?
readstream nodejs (5)
Escribí una función bastante simple que descarga una imagen desde una URL dada, la redimensiono y la subo a S3 (usando ''gm'' y ''knox''), no tengo idea si estoy haciendo la lectura de un flujo a un búfer correctamente . (Todo está funcionando, pero ¿es la forma correcta?)
también, quiero entender algo sobre el bucle de eventos, ¿cómo puedo saber que una invocación de la función no filtrará nada o cambiará la variable ''buf'' a otra invocación que ya se está ejecutando (o este escenario es imposible porque las devoluciones de llamada son anónimas?) funciones?)
var http = require(''http'');
var https = require(''https'');
var s3 = require(''./s3'');
var gm = require(''gm'');
module.exports.processImageUrl = function(imageUrl, filename, callback) {
var client = http;
if (imageUrl.substr(0, 5) == ''https'') { client = https; }
client.get(imageUrl, function(res) {
if (res.statusCode != 200) {
return callback(new Error(''HTTP Response code '' + res.statusCode));
}
gm(res)
.geometry(1024, 768, ''>'')
.stream(''jpg'', function(err, stdout, stderr) {
if (!err) {
var buf = new Buffer(0);
stdout.on(''data'', function(d) {
buf = Buffer.concat([buf, d]);
});
stdout.on(''end'', function() {
var headers = {
''Content-Length'': buf.length
, ''Content-Type'': ''Image/jpeg''
, ''x-amz-acl'': ''public-read''
};
s3.putBuffer(buf, ''/img/d/'' + filename + ''.jpg'', headers, function(err, res) {
if(err) {
return callback(err);
} else {
return callback(null, res.client._httpMessage.url);
}
});
});
} else {
callback(err);
}
});
}).on(''error'', function(err) {
callback(err);
});
};
En general no veo nada que pueda romper tu código.
Dos sugerencias:
La forma en que se combinan los objetos de Buffer
es un subóptimo porque tiene que copiar todos los datos preexistentes en cada evento de "datos". Sería mejor poner los trozos en una matriz y concat
al final.
var bufs = [];
stdout.on(''data'', function(d){ bufs.push(d); });
stdout.on(''end'', function(){
var buf = Buffer.concat(bufs);
}
Para el rendimiento, analizaría si la biblioteca S3 que está utilizando admite transmisiones. Lo ideal sería que no necesitara crear un búfer grande, y en lugar de eso, simplemente pase la secuencia stdout
directamente a la biblioteca S3.
En cuanto a la segunda parte de tu pregunta, eso no es posible. Cuando se llama a una función, se le asigna su propio contexto privado, y todo lo que está definido dentro solo será accesible desde otros elementos definidos dentro de esa función.
Actualizar
Descargar el archivo al sistema de archivos probablemente significaría menos uso de memoria por solicitud, pero la E / S de archivos puede ser bastante lenta, por lo que podría no valer la pena. Yo diría que no debería optimizar demasiado hasta que pueda realizar un perfil y realizar una prueba de estrés de esta función. Si el recolector de basura hace su trabajo, es posible que esté exagerando.
Con todo lo dicho, hay formas mejores de todos modos, así que no uses archivos. Como lo único que desea es la longitud, puede calcularlo sin tener que agregar todos los búferes, por lo que no necesita asignar un Buffer nuevo.
var pause_stream = require(''pause-stream'');
// Your other code.
var bufs = [];
stdout.on(''data'', function(d){ bufs.push(d); });
stdout.on(''end'', function(){
var contentLength = bufs.reduce(function(sum, buf){
return sum + buf.length;
}, 0);
// Create a stream that will emit your chunks when resumed.
var stream = pause_stream();
stream.pause();
while (bufs.length) stream.write(bufs.shift());
stream.end();
var headers = {
''Content-Length'': contentLength,
// ...
};
s3.putStream(stream, ....);
Puede hacer esto fácilmente usando node-fetch si está sacando de http (s) URI.
Desde el readme:
fetch(''https://assets-cdn.github.com/images/modules/logos_page/Octocat.png'')
.then(res => res.buffer())
.then(buffer => console.log)
Solo quiero publicar mi solución. Las respuestas anteriores fueron bastante útiles para mi investigación. Utilizo el flujo de longitud para obtener el tamaño del flujo, pero el problema aquí es que la devolución de llamada se activa casi al final del flujo, así que también uso el caché de flujo para almacenar en caché el flujo y canalizarlo para resoplar el objeto una vez que lo sepa la longitud del contenido. En caso de un error,
var StreamCache = require(''stream-cache'');
var lengthStream = require(''length-stream'');
var _streamFile = function(res , stream , cb){
var cache = new StreamCache();
var lstream = lengthStream(function(length) {
res.header("Content-Length", length);
cache.pipe(res);
});
stream.on(''error'', function(err){
return cb(err);
});
stream.on(''end'', function(){
return cb(null , true);
});
return stream.pipe(lstream).pipe(cache);
}
Sugiero tener una matriz de buffers y concat para el buffer resultante solo una vez al final. Es fácil de hacer manualmente, o uno podría usar node-buffers
Un proyecto relacionado es node-stream-buffer . Descripción: "Flujos legibles y legibles que utilizan búferes de respaldo".