Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Function similar to Promise.some/any for an unknown amount of promises

I am creating a script in node.js (V8.1.3) which looks at similar JSON data from multiple API's and compares the values. To be more exact I am looking at different market prices of different stocks (actually cryptocurrencies).

Currently, I am using promise.all to wait for all responses from the respective APIs.

let fetchedJSON =
        await Promise.all([getJSON(settings1), getJSON(settings2), getJSON(settings3) ... ]); 

However, Promise.all throws an error if even just one promise rejects with an error. In the bluebird docos there is a function called Promise.some which is almost what I want. As I understand it takes an array of promises and resolves the two fastest promises to resolve, or otherwise (if less than 2 promises resolve) throws an error.

The problem with this is that firstly, I don't want the fastest two promises resolved to be what it returns, I want any successful promises to be returned, as long as there is more than 2. This seems to be what Promise.any does except with a min count of 1. (I require a minimum count of 2)

Secondly, I don't know how many Promises I will be awaiting on (In other words, I don't know how many API's I will be requesting data from). It may only be 2 or it may be 30. This depends on user input.

Currently writing this it seems to me there is probably just a way to have a promise.any with a count of 2 and that would be the easiest solution. Is this possible?

Btw, not sure if the title really summarizes the question. Please suggest an edit for the title :)

EDIT: Another way I may be writing the script is that the first two APIs to get loaded in start getting computed and pushed to the browser and then every next JSON that gets loaded and computed after it. This way I am not waiting for all Promises to be fulfilled before I start computing the data and passing results to the front end. Would this be possible with a function which also works for the other circumstances?

What I mean kind of looks like this:

Requesting JSON in parallel...

|-----JSON1------|

|---JSON-FAILS---| > catch error > do something with error. Doesn't effect next results.

|-------JSON2-------| > Meets minimum of 2 results > computes JSON > to browser.

|-------JSON3---------| > computes JSON > to browser.

like image 852
Manu Masson Avatar asked Jun 30 '17 15:06

Manu Masson


1 Answers

How about thening all the promises so none fail, pass that to Promise.all, and filter the successful results in a final .then.

Something like this:

function some( promises, count = 1 ){

   const wrapped = promises.map( promise => promise.then(value => ({ success: true, value }), () => ({ success: false })) );
   return Promise.all( wrapped ).then(function(results){
      const successful = results.filter(result => result.success);
      if( successful.length < count )
         throw new Error("Only " + successful.length + " resolved.")
      return successful.map(result => result.value);
   });

}
like image 197
pishpish Avatar answered Oct 18 '22 10:10

pishpish