Recently we were implementing a feature in our app that resulted in a nice kata-like task, encouraging me to play with JavaScript Promises and deepening my knowledge of them. Illustration of by Autocomplete Martin Bonov The task: For an autocomplete there are several services to ask for suggestions on user input. Those services are ordered from our own servers (cheap), to partners', to Google's (expensive). We want to show the user the first non-empty response. Moreover, we want to ask the next service only if the previous service suggested no items. Oh, and one part that resembled the kata, too, was that I had a lot of fun solving it. Problem in a kata form In technical terms a is an asynchronous function which returns a promise. This promise, when resolved, contains an array of suggestions. The array can be empty. Please note that an empty result is different to rejecting the promise. service Given a list of these invoke each , wait for its result, and then either return the result if non-empty or continue with the next . services service service Now it's the time to try it yourself—if you want to—before I show my solution. Start with this : boilerplate with basic test cases Existing libraries and solutions A small obstacle in my research for existing solutions was that I did not know how to describe it in keywords. In the end I tried ‘first’, ‘sequence’, ‘cascade’, ‘waterfall’, and ‘fallback’ combined with the obvious ‘promise’. Then I had to filter out numerous results describing or . Promise.all Promise.race promise-fallback After some research I found this NPM package which basically solves the problem. It uses a (rather cumbersome) recursion and overall is neither easily understandable nor elegant. See the on GitHub (in CoffeeScript). However, it could be used for our needs. code mutatis mutandis Executing Promises in Sequence The second approach for a similar task (first existing file in a file names list) is explained in a more recent article by . It also takes advantage of recursion. Although it feels tidier (no CoffeeScript helps 😜), I cannot say it reads well. The author himself concludes with a question ‘Do you have a more elegant approach?’ Cory LaViska My solution Still, I hoped for an approach that would be small, readable, and maintainable. My ideal solution would be analogous to middlewares. koa Iteration 1: Promise.reduce, Koa, and wrappers In the end, Cory's article has proven to be extremely useful as it pointed me to the Bluebird documentation where I discovered . Promise.reduce Middleware architecture on a by slide Jon Crosby While is meant for different usages—e.g. summing content of multiple files—it performs one important thing. When going through the array ‘the result of the promise is awaited, before continuing with next iteration.’ Promise.reduce Instead of recursively calling the fallback function, I wanted to create a promise chain. So I wrapped each in a wrapper function that receives the latest result . Then if this result is empty it calls the service and returns the promise it receives. In the other way it simply passes on the result—as if the path does not match in a koa middleware. service so far It looks like this: const myServiceWrapper = (latestResult) =>!latestResult.length? myService(userInput): latestResult const partnerServiceWrapper = …const googleServiceWrapper = … Such wrappers can easily be chained: Promise.resolve([]).then(myServiceWrapper).then(partnerServiceWrapper).then(googleServiceWrapper) Here serves as a of the promise chain. Thanks to it we can immediately use . Also, it sets the for the first wrapper to . Promise.resolve([]) starter then latestResult [] Eureka! This solves our problem! nearly Iteration 2: Reduce to five lines These wrappers are simple, readable, and independent. Which hence means maintainable. So what is left to come? Firstly, we do not want to write the boilerplate. Secondly, the number of is unknown. We want to pass our function just a given array of . services services Coincidently, we solve them both in one step. An important hint here is the name of aforementioned . Promise.reduce The five (!) line solution does exactly the same as the wrappers chain above for any number of services using (Ooooh! 😃). Array.reduce We start the chain again with , then in each iteration is a promise and is a . Promise.resolve([]) prev next service const firstResult = (services, userInput) => services.reduce((prev, next) => prev.then((result) =>!result.length ? next(userInput) : result),Promise.resolve([])) Generalised solution Later I generalised the code for any ‘ ’ use case. S_ervices_ are now ambiguous . first non-empty result in a sequence of promises tasks Do you like ? See the solution with type annotations below! Flow As the second argument you can pass some options (with default values): : Arguments to be passed to each args=[] task : A value to the promise chain with initial=undefined start : A function to determine if the result is empty. Should be fast as it is run repeatedly. isEmpty=(x) => !x Remarks Because the code is five lines I decided not to publish it as an standalone NPM package. Or should I? de facto As mentioned, number of times the function is called is always the same as the number of tasks. This is a drawback of isolation. isEmpty In the example, is not a good real-world condition as it would throw an exception if the was undefined. !result.length result When any of the is rejected the whole encapsulating promise is also rejected. tasks Bonus: Solution with Flow type annotations For clarity I present the solution above with type annotations, which make the whole code a bit longer; although, the main part is still about five lines. Flow Note that the generic type corresponds to the results of the and, hence, to the overall result. T tasks Notation means that the type is , see . ?T nullable explanation Do you find the Flow annotations helpful? Does it add value for you? Should I keep adding them? Please help: 👏 . If you like this post, please don’t forget to give a below Every clap notification is a motivational boost for me. If you would like to learn more, I recently started a YouTube channel about JavaScript. I post new video every week, so consider subscribing. Be there from the beginning and help me get better. _JavaScript is my passion: I like to write JavaScript, I like to read JavaScript, and I like to talk JavaScript._www.youtube.com/c/robinpokorny Robin Pokorny on YouTube Related articles by Executing Promises in Sequence (and Stopping at the First Resolved Promise) Cory LaViska in Bluebird docs Promise.reduce