3

For the below code, how to call the downloadFile() function sequentially for each of the entry in the arrUrls[] - using the npm Q promise library, so that only one file gets downloaded at a time.

var q = require("q");

var arrUrls = ['http://1.com', 'http://2.com']; //content/length of this array will actually be dynamic.


var downloadFile = function(link)
{
    var deferred = q.defer();

    var requesthandler = function(url, error, response, html)
    {
        //format response and return
        deferred.resolve(response);
    }

    request(urloptions, requesthandler.bind(null, link));

    return deferred.promise;
};

I know this can be done straight forward using npm async library's async.mapSeries(). But, async uses callback approach, and I would prefer a solution using promise if possible.

Dan
  • 101
  • 1
  • 11
  • @Bergi, the [http://stackoverflow.com/questions/18386753/how-to-sequentially-run-promises-with-q-in-javascript] `How to sequentially run promises with Q in Javascript?` pointed above would not exactly help here. Please notice that the `downloadFile` function asynchronously return 'formatted response'. So, at the end I would like to have an array/collection of formatted responses. – Dan Mar 05 '15 at 23:59

1 Answers1

0

For a purely sequential solution, you could build a promise chain with a recursive function that adds each result.

function wrap(func){
    return function(results) {
        var result = func();
        results.push(result);
        return results;
    };
}

var funcs = [loadFile(x),loadFile(y), loadFile(z)];
var wrapped = funcs.map(wrap);

wrapped
  .reduce(q.when, q([]))
  .then(function(results){
       //results array
});

basically it builds the standard promise chain, and uses the reduce as a shortcut to unfold the function calls into the "result array".

If you don't need exact sequential calls:

You can get values returned in sequence by making an array of requests/promises.

var requests = [downloadFile('http://blah'), downloadFile('http://blah2')];

q.all(requests).then(function(results) {
    //results will be an array of your results, in order of index
});

See Combination in the doc: You can turn an array of promises into a promise for the whole, fulfilled array using all.

FlavorScape
  • 13,301
  • 12
  • 75
  • 117
  • I tried your pseudo code, there are two issues:. 1. both the `downloadFile('http://blah')` and `downloadFile('http://blah2')` gets executed immediately when the execution reaches the line: `var requests = [downloadFile('http://blah'),downloadFile('http://blah2') ];` . 2. q.all executed the methods parallel (not sequentially). – Dan Mar 05 '15 at 21:17
  • Reply to the updated answer: I'm not worried how I get the result (sequentially or not). I would like one out going network connection by my code at a time (i.e, one `downloadFile()` call at a time) – Dan Mar 05 '15 at 21:27
  • the q.all should really have a thread limiter param. It's a shame. But, if you're going to use HTTP2, who cares! – FlavorScape Mar 05 '15 at 23:09
  • `q.all` cannot have any such parameter. that is not how javascript libraries work. Javascript engine will not (or should not) expose any thread related stuff to the client code (in this case to the Q library). The problem in question is more related to `async programming`....which I'm still trying to get my head around. – Dan Mar 06 '15 at 00:04
  • I really meant client connections, not threads in my quick response. But, if the implementation uses js workers to load the xhr, why not parametize that? "not how javascript libraries work" makes no sense. – FlavorScape Mar 06 '15 at 00:22
  • In fact, promises are great for waiting on asynchronous worker threads in and of themselves. I'm certain that the xhr request under the hood would be threaded in a similar fashion. "The problem in question is more related to async programming" well that's exactly what async is, it's executing in a different execution thread, and therefore out of sync with the main thread. – FlavorScape Mar 06 '15 at 00:25