Saving multiple files using Promises

44 views
Skip to first unread message

Ank

unread,
Aug 27, 2016, 6:35:24 PM8/27/16
to nodejs

I have a Node URL (created using Express) that can be used to download a static image of an address. So, the calling app calls the /download url and passes multiple addresses using json, then the download service would call the Google Maps service and save the static image of each of these addreses on the node server (it would then send it back to the calling application, but for the purpose of this question I am only interested in saving the images in the node server).

Initially, we were only interested in saving satellite view of the addresses, so I wrote this code

var request = require('request');
function saveMap(addressJson) {
   
return Promise.all(
       
//iterate over address json, get each address, call the Google Maps URL and save it.
 addressJson
.map(function(item) {
             
return new Promise(function (resolve, reject) {
                 
var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=roadmap&markers=size:mid|color:red|' + item.address;
                 request
(mapUrl)
                     
.pipe(fs.createWriteStream('/temp/' + item.id + '.jpg'))
                     
.on('finish', function () {
                         resolve
("Promise resolved");
                     
}).on('error', function (error) {
                         reject
('Error in creating map', error);
                     
})
             
});
       
})
   
)
}


The Promises for saving each address is wrapped inside Promise.all(..), since I want to the saveMap() to return when all maps have finished downloading (so that I can zip them and send to the calling app, so need to be sure that everything has been downloaded).

Now, we need to extend this function to also include satellite maps. so, I was hoping, that within same json iteration, I can have another Promise which would download satellite maps. Something like this 

 
function saveMap(addressJson) {
   
return Promise.all(
       
//iterate over address json, get each address, call the Google Maps URL and save it.
 addressJson
.map(function(item) {
             
return new Promise(function (resolve, reject) {
                 
var mapUrl = 'http://maps.googleapis.com/maps/api/staticmap?maptype=roadmap|' + item.address;
                 request
(mapUrl)
                     
.pipe(fs.createWriteStream('/temp/r/' + item.id + '.jpg'))
                     
.on('finish', function () {
                         resolve
("Promise resolved");
                     
}).on('error', function (error) {
                         reject
('Error in creating map', error);
                     
})
             
});
 
return new Promise(function (resolve, reject) {
                 
var mapUrl2 = 'http://maps.googleapis.com/maps/api/staticmap?maptype=satellite|' + item.address;
                 req
(mapUrl2)
                     
.pipe(fs.createWriteStream(fs.createWriteStream('/temp/s/' + item.id + '.jpg'))
                     
.on('finish', function () {
                         resolve
("Promised resolved");
                     
}).on('error', function (error) {
                         reject
('Error in creating map', error);
                     
})
             
});
       
})
   
)
}


However, this does not work as expected. I don't get an error but it is not generating all the jpg files. Can someone please help me understand what I am doing wrong and how to get this corrected.

Zlatko

unread,
Aug 28, 2016, 3:05:16 AM8/28/16
to nodejs
You seem to be passing 2 args to your addresses.map() callback ( can't tell exactly on phone:(). But if you do, the second arg is simply used as function context ('this'). You don't use it so it's never called.

Perhaps try something different:

Promise.all(addresses.map (item => getMap(item))
.concat (addresses.map(item => getSateliteMap(item)));

That would fire all requests in parallel, so maybe you should make sure to limit your batch size. Probably a wrapper for this function which chunks up the array into batches and runs the batches in series, and informs the original request when everything was returned.

Additionally you might consider not rejecting that error; that seemingly terminates all other requests without waiting for their results. Maybe instead write down which reqs failed and in the end you will have more details on how things went.
Reply all
Reply to author
Forward
0 new messages