Over a million developers have joined DZone.

How to Run a Promise Waterfall

How to run a series of promises in sequence like a waterfall, while also solving a race condition.

· Java Zone

Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code! Brought to you in partnership with ZeroTurnaround.

I use promises a lot in my development process. I find them extremely pliable for my needs. However, for whatever reason, I don't use abstractions for most of my development, which is to say I use vanilla promises unencumbered by an additional API to learn.

Recently I needed to run a series of promises, but I had to also solve a race condition, so they had to run in sequence (i.e. a waterfall). I know libraries like async.js have this baked in, but I wanted to write up how to go about doing it without a library.

The Setup

In my particular case I was running promises that took an undetermined amount of time to complete. In the interest of keeping things simple, let's say the following is what the promise has to run, and it will return a sequence number:

var guid = 0;
function run() {
  guid++;
  var id = guid;
  return new Promise(resolve => {
    // resolve in a random amount of time
    setTimeout(function () {
      console.log(id);
      resolve(id);
    }, (Math.random() * 1.5 | 0) * 1000);
  });
}

First in Parallel

To get values 1..10 I would then call the run function via an array of promises through Promise.all (note that this is run in parallel and not in sequence at this point):

// make an array of 10 promises
var promises = Array.from({ length: 10 }, run);

Promise.all(promises).then(console.log);
// => [1,2,3,4,5,6,7,8,9,10]

Note that the console logs in the bin below are out of order, but the final result is correct (which is what we'd expect with Promise.all):

Now as a Waterfall

Promises naturally waterfall into each other, but for an undetermined length of an array, I need to recursively chain the promises together, passing the aggregate result from the previous promise into the next, and so on. A perfect match for [].reduce.

var promise = Array.from({ length: 10 }).reduce(function (acc) {
  return acc.then(function (res) {
    return run().then(function (result) {
      res.push(result);
      return res;
    });
  });
}, Promise.resolve([]));

promise.then(console.log);

Remember that the Array.from({ length: 10 }) is simply generating an array from 0 to 9 for this demo purpose. Also note that run() is inside the reduce function, and the end result is no longer an array of promises, but in fact a single promise (and so I drop the use of Promise.all).

Now you can see from the JS Bin below that the promises run in sequence (I've added a console):

var guid = 0;
function run() {
guid++;
var id = guid;
return new Promise(resolve => {
// resolve in a random amount of time
setTimeout(function () {
console.log(id);
resolve(id);
}, (Math.random() * 1.5 | 0) * 1000);
});
}

var promises = Array.from({ length: 10 }).reduce(function (acc) {
return acc.then(function (res) {
return run().then(function (result) {
res.push(result);
return res;
});
});
}, Promise.resolve([]));

promises.then(console.log);

Worth Noting

Obviously the waterfall of promises is going to take longer to complete than a parallel run of the promises, but as I mentioned at the start of this post, I needed to solve a race condition, and this was the solution I needed.

The Java Zone is brought to you in partnership with ZeroTurnaround. Check out this 8-step guide to see how you can increase your productivity by skipping slow application redeploys and by implementing application profiling, as you code!

Topics:
javascript ,async ,promises ,promises in javascript

Published at DZone with permission of Remy Sharp, DZone MVB. See the original article here.

Opinions expressed by DZone contributors are their own.

The best of DZone straight to your inbox.

SEE AN EXAMPLE
Please provide a valid email address.

Thanks for subscribing!

Awesome! Check your inbox to verify your email so you can start receiving the latest in tech news and resources.
Subscribe

{{ parent.title || parent.header.title}}

{{ parent.tldr }}

{{ parent.urlSource.name }}