Executing Promises in Sequence (and Stopping at the First Resolved Promise)

Here's a challenge that a friend of mine came across yesterday. He needed to iterate over an array of file names one at a time in a specific order, stopping at the first one that existed. He was, of course, using Node.js and the checks were being done asynchronously.

The Problem

You might think this would be easy, especially if you're using a promise library such as Bluebird, but it's not as simple as it sounds. Since promises execute in parallel, there's no guarantee of which one will resolve first.

To do what my friend needed to do, we had to wait for each promise to complete before moving on to the next one (i.e. run them in sequence).

The Solution

The solution I came up with uses recursion to iterate over an array of values. It passes them one by one to an async function of your choice. It runs in sequence and stops on the first resolved promise.

function firstInSequence(values, asyncFn) {  
  return new Promise(function(resolve, reject) {
    // Are there any values to check?
    if(values.length === 0) {
// All were rejected
} // Try the first value asyncFn(values[0]).then(function(val) { // Resolved, we're all done resolve(val); }).catch(function() { // Rejected, remove the first item from the array and recursively // try the next one values.shift(); firstInSequence(values, asyncFn).then(resolve).catch(reject); }); }); } // Some async function... function yourAsyncFunction(val) { return new Promise(function(resolve, reject) { // Brief pause to show sequence setTimeout(function() { if(val >= 3) { resolve(val); } else { reject(val); } }, 500); }); } // Example usage firstInSequence([1, 2, 3, 4, 5], yourAsyncFunction).then(function(val) { console.log('Resolved on ' + val); }).catch(function() { console.log('All were rejected'); });

While I appreciate the asynchronous nature of Node.js, sometimes the world needs a bit of order.

What do you think? Do you have a more elegant approach?

Simple, Beautiful Publishing

This website is powered by Postleaf, an open source blogging platform I built myself. Check it out if you’re looking for a fresh, modern approach to content management.

Author avatar

About the author

Cory LaViska is a founder, web developer, and bootstrapper based in Orlando, Florida. Need to get in touch? You can connect with him on Twitter. Looking for a simple, no-worry CMS for your clients? Try my Surreal CMS!