I have the following code where it grabs one of the 6 URLs, strips the filename, creates a filepath, saves image file to disk, sends it off to MongoDB GridFS. The only thing that's changing is image size: 32px, 64px, 128px, 256px, 512px, 1024px. Bruteforce approach is to just copy and paste this code 6 times, and you can only imagine what a mess that would be.
How can I place this code inside for-loop where 32 would change to 64, 128, 256, 512, 1024 for each loop iteration?
var filename32 = image32.replace(/^.*[\\\/]/, '');
var filepath32 = path.join(__dirname, filename32);
var writestream32 = gfs.createWriteStream({ filename: filename32 });
var imageStream32 = request(image32).pipe(fs.createWriteStream(filepath32));
imageStream32.on('close', function() {
fs.createReadStream(filepath32).pipe(writestream32);
fs.unlink(filepath32);
});
Ok so this problem is impossible to solve using iterative approach. More info here: node.js: while loop callback not working as expected. TLDR: Because node.js and javascript are single threaded.
Something like this? I'm not sure what actually needs to have the image size appended to it, I just guessed the file name.
for(var i=32; i <= 1024; i*=2) {
var filename = image.replace(/^.*[\\\/]/, '') + i;
var filepath = path.join(__dirname, filename);
var writestream = gfs.createWriteStream({ filename: filename });
var imageStream = request(image).pipe(fs.createWriteStream(filepath));
imageStream.on('close', function() {
fs.createReadStream(filepath).pipe(writestream);
fs.unlink(filepath);
});
}
Using arrays? I'm not sure I understand your problem correctly because this solution seems silly...
// use this array to store file names(urls).
var imagesName = new Array("32.png", "128.png", "256.png", "512.png", "1024.png");
for (var i = 0; i < imagesName.length; i++) {
var filename = imagesName[i].replace(/^.*[\\\/]/, '');
var filepath = path.join(__dirname, filename);
var writestream = gfs.createWriteStream({ filename: filename });
var imageStream = request(imagesName[i]).pipe(fs.createWriteStream(filepath));
imageStream32.on('close', function() {
fs.createReadStream(filepath).pipe(writestream);
fs.unlink(filepath);
});
}
You don't need an array if all you're doing is doubling the size each time. It's trivial to calculate powers of two, as @bitwiser's answer shows.
But both of the previous answers have a bug. They use the filepath and writestream variables in the imageStream32.on('close') callback, however, this callback is called asynchronously, after the for loop finishes executing. So all of these callbacks use the last value that these two variables received the last time through the loop, instead of the correct values from the proper loop iteration.
It's easy to fix this: You simply need to call a function for each loop iteration instead of putting the code directly inside the loop body. The function call creates a closure which preserves those variables individually for each image, so you will write and close the correct file for each image.
Also, you didn't define the image32 variable that the filenames are generated from. Do you really need the complicated regular expression here; don't you know what the image filenames should be? I'm going to assume the filenames are 'image32'…'image1024', but you can easily change that of course.
So the code would look like this:
function processImages( basename, minSize, maxSize ) {
for( var size = minSize; size <= maxSize; size *= 2 ) {
processImage( size );
}
function processImage( size ) {
var filename = basename + size;
var filepath = path.join( __dirname, filename );
var writestream =
gfs.createWriteStream({ filename: filename });
var imageStream =
request(image).pipe( fs.createWriteStream(filepath) );
imageStream.on( 'close', function() {
fs.createReadStream(filepath).pipe(writestream);
fs.unlink(filepath);
});
}
}
processImages( 'image', 32, 1024 );