Gokhan Dilek
Gokhan Dilek

Reputation: 4402

How to trigger a function after all the downloads are finished

I would like to give you a background first.

I have an array of image parameters just like below:

    "imageParameters": [
      {
        "imageparam1": "param1",
        "imageparam2": "param2",
        "imageparam3": "param3"
      },

      {
        "imageparam1": "param1",
        "imageparam2": "param2",
        "imageparam3": "param3"
      }
    ]

I loop through this to generate unique urls per image. Then trigger the downloadImageAndSave function each time url is generated.

imageParameters.forEach(function (image) {
var imageUrL = baseURL + "&param1=" + image.imageparam1 + "&param2=" + image.imageparam2 + "&param3=" + image.imageparam3 ;

var imageparam1 = image.imageparam1;
downloadImageAndSave(imageUrL, imageparam1);   

    });

function downloadImageAndSave(imageUrL, imageparam1) {

    console.log("Download function is triggered")
    var fs = require('fs'),
        request = require('request');

    request
        .get(imageUrL)
        .on('error', function(err) {
            // handle error
        })
        .pipe(fs.createWriteStream('./imagesLocation/' + imageparam1 + '.jpeg'));

myfunctionTobeTRiggeredAfterImagesDownloadedAndSaved();
}

How do I know all of these images are downloaded and saved so that I can trigger my function?

The problem I am having is to use the callback. I am not how I can get callback once all of the images are downloaded and saved.

Any help would be much appreciated. Thank you.

UPDATED

Below is the workflow I am trying to achieve. I get an input from the user via express API like this.

 app.get('/getStudyID', function(req, res) {
   var id = req.query['getStudyID'];
   //pass this to a variable to be used by various functions.
   downloadImagesToNodeServer(id);
   zipImageFiles();
   returnTheZipFileBackToUser(id);

   }

Then return the zipped file which contains the images back to the user.

  function returnTheZipFileToUser(id) {

    var path = require('path');
    var mime = require('mime');
    var file = __dirname + '/public/imagelocation/' + id + '.zip';
    var filename = path.basename(file);
    var mimetype = mime.lookup(file);

    res.setHeader('Content-disposition', 'attachment; filename=' + filename);
    res.setHeader('Content-type', mimetype);

    var filestream = fs.createReadStream(file);
    filestream.pipe(res);
 }

The returnTheZipFileToUser is called too early before the images are downloaded and zipped. Therefore I get the image.zip file not found problem as it is triggered way too early before the zipImageFiles() and downloadImagesToNodeServer.

I found a hacky way to implement the setTimeout to wait for the downloads to finish then trigger the returnTheZipFileToUser(id). But this is not a real solution as the timing is different depending on the size of the images and the zip file. So I need a surefire way that the images are downloaded completely and zipped file is ready before the returnTheZipFileToUser is called.

Upvotes: 1

Views: 448

Answers (1)

pgreen2
pgreen2

Reputation: 3651

If you return the stream from downloadImageAndSave, you could then use something like stream-concat to concat all of the streams into a single stream that you could listen for the finish event:

function downloadImages(imageParameters, cb) {

  var streams = imageParameters.map(function (image) {
    var imageUrL = baseURL + "&param1=" + image.imageparam1 + "&param2=" + image.imageparam2 + "&param3=" + image.imageparam3 ;

    var imageparam1 = image.imageparam1;
    return downloadImageAndSave(imageUrL, imageparam1);
  });

  var combinedStream = new StreamConcat(streams);
  combinedStream.on('error', function(error) {
    cb(error);
  });
  combinedStream.on('finish', function() {
    cb();
  });
}

function downloadImageAndSave(imageUrL, imageparam1) {

    console.log("Download function is triggered")
    var fs = require('fs'),
        request = require('request');

    return request
        .get(imageUrL)
        .on('error', function(err) {
            // handle error
        })
        .pipe(fs.createWriteStream('./imagesLocation/' + imageparam1 + '.jpeg'));
}

Upvotes: 2

Related Questions