I have an array that contains filenames at each index. I want to download those files one at a time (synchronously). I know about 'Async
' module. But I want to know whether any functions in Lodash
or Underscore
or Bluebird
library supports this functionality.
Asked
Active
Viewed 2,857 times
9

Nidhin David
- 2,426
- 3
- 31
- 45
2 Answers
6
You can use bluebird's Promise.mapSeries
:
var files = [
'file1',
'file2'
];
var result = Promise.mapSeries(files, function(file) {
return downloadFile(file); // << the return must be a promise
});
Depending on what you use to download file, you may have to build a promise or not.
Update 1
An exemple of a downloadFile()
function using only nodejs:
var http = require('http');
var path = require('path');
var fs = require('fs');
function downloadFile(file) {
console.time('downloaded in');
var name = path.basename(file);
return new Promise(function (resolve, reject) {
http.get(file, function (res) {
res.on('data', function (chunk) {
fs.appendFileSync(name, chunk);
});
res.on('end', function () {
console.timeEnd('downloaded in');
resolve(name);
});
});
});
}
Update 2
As Gorgi Kosev suggested, building a chain of promises using a loop works too:
var p = Promise.resolve();
files.forEach(function(file) {
p = p.then(downloadFile.bind(null, file));
});
p.then(_ => console.log('done'));
A chain of promise will get you only the result of the last promise in the chain while mapSeries()
gives you an array with the result of each promise.

Shanoor
- 13,344
- 2
- 29
- 40
-
Without mapSeries: `var downloads = []; for (var p = Promise.pending(), i = 0; i < files.length; ++i) downloads.push(p = p.then(_ => downloadFile(files[i]))); return Promise.all(downloads)` – Gjorgi Kjosev Dec 24 '15 at 12:54
-
@GorgiKosev Your code doesn't work but yes, building a chain of promises would work too. However, using `Promise.all()` here is wrong, you're doing a `Promise.all([p, p, p])`, each file will be downloaded multiple times. I'll update my answer with your suggestion. – Shanoor Dec 24 '15 at 18:55
-
No, thats not correct. A promise represents an operation that was already started, and trying to chain to it multiple times will not cause the same operation to be repeated. Its completely okay to use `Promise.all` just as its okay to attach multiple `then` callbacks to a single promise. – Gjorgi Kjosev Dec 25 '15 at 23:28
-
You're right (object's reference and stuff) but Promise.all is still useless in this case, p.then() is enough. – Shanoor Dec 26 '15 at 05:03
-
Yes, if there is no data to return within the promises, there is no reason to use `Promise.all` – Gjorgi Kjosev Dec 27 '15 at 01:02
1
using Bluebird, there is a situation similar to yours with an answer here: How to chain a variable number of promises in Q, in order?
This seems like a decent solution but in my opinion much less readable and elegant as async.eachSeries(I know you said you don`t want the 'async' solution but maybe you can reconsider.