How to run a promise-then chain using map or reduce on an arbitrary number of chain elements?

frequent picture frequent · May 4, 2014 · Viewed 9.4k times · Source

I'm stuck on the following:

A script is returning an arbitrary number n or array, like this:

[["a"], ["b"], ["c"], ["d"]]

I need to loop over the arrays using promise then(), but as I don't know how many elements there will be, I have ended up doing this:

  var bundle_list = [["a"], ["b"], ["c"], ["d"]];

  var x = bundle_list.reduce(function(current, next) {
  console.log(current);

  // requestBundle will also return a promise
  return requestBundle(current)
    .then(function(bundle_response) {
      // do foo
      console.log("CALLING NEXT")
      console.log(next);
      return RSVP.resolve(next);
    });
})

x.then(function(last_response) {
  return console.log("DONE")
});

My problem is that my reduce/map both trigger all iterations before my async code is run, so I'm getting 3x the current console followed by the done console. So all my map "loop" run instantly, with the results clocking in a little (too) later...

I'm using this RSVP implementation, but it's A+ so should not be a problem. I have been trying to work along the answer provided here, but I cannot get it to work properly.

Question:
Is it possible to create a "then-chain" with an arbitrary number of then statements. If so, some pointers are appreciated!

Thanks!

Answer

Benjamin Gruenbaum picture Benjamin Gruenbaum · May 4, 2014

A for (or forEach) loop should do:

var queue = RSVP.Promise.resolve(); // in ES6 or BB, just Promise.resolve();

bundle_list.forEach(function(el){
    queue = queue.then(function(res){
        console.log("Calling async func for", el);
        return requestBundle(el);
    });
});

queue.then(function(lastResponse){
    console.log("Done!");
});