The function is similar to Promise.some / any for an unknown amount of promises.

I am creating a script in node.js (V8.1.3) that looks at similar JSON data from several APIs and compares the values. More precisely, I look at different market prices of different stocks (actually cryptocurrencies).

I am currently using promise.all to wait for all responses from the corresponding APIs.

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

However, Promise.all throws an error if at least one promise is rejected with an error. There is a Promise.some function in the Bluebird documentation, and that is almost what I want. As I understand it, it accepts an array of promises and resolves the two fastest promises that are resolved, or otherwise (if less than two promises are resolved) gives an error.

The problem is that, firstly, I do not want the two fastest promises to be resolved as returnable, I want any successful promises to be returned if there are more than 2. This seems to be what Promise.any does, except that the minute counter is 1. (I need a minimum score of 2)

Secondly, I do not know how many promises I will expect (in other words, I do not know how many APIs I will request data from ). It can only be 2 or 30. It depends on user input.

Now, when I write this, it seems to me that there is simply a way to get a promise. Anyone with a score of 2, and that would be the easiest solution. Is it possible?

By the way, not sure if the headline really summarizes the question. Please suggest changing the name :)

UPDATE: Another way I can write a script is that the first two downloadable APIs start to be computed and passed to the browser, and then every next JSON that is loaded and computed after it. Thus, I do not wait for all Promises to be fulfilled before I begin to calculate the data and transfer the results to the external interface. Is this possible with a function that also works for other circumstances?

What I mean looks something like this:

JSON request in parallel ...

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

| --- JSON-FAILS --- | > catch an error> do something with an error. Does not affect the following results.

| ------- JSON2 ------- | > Matches at least 2 results> calculates JSON> for the browser.

| ------- JSON3 --------- | > computes JSON> for the browser.

+8
source share
3 answers

How about then all promises, so no one will work, go to Promise.all and filter the successful results in the final .then .

Something like that:

 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); }); } 
+5
source

This might be somewhat awkward, given that you are asking to implement an anti-pattern, but you can make every promise resolve:

 async function fetchAllJSON(settingsArray) { let fetchedJSON = await Promise.all( settingsArray.map((settings) => { // force rejected ajax to always resolve return getJSON(settings).then((data) => { // initial processing return { success: true, data } }).catch((error) => { // error handling return { success, false, error } }) }) ).then((unfilteredArray) => { // only keep successful promises return dataArray.filter(({ success }) => success) }) // do the rest of your processing here // with fetchedJSON containing array of data } 
+1
source

Other answers have a flip side: you need to wait until all promises are resolved, while ideally .some will return as soon as any (N) promise (s) passes the predicate.

 let anyNPromises = (promises, predicate = a => a, n = 1) => new Promise(async resolve => { promises.forEach(async p => predicate(await p) && !--n && resolve(true)); await Promise.all(promises); resolve(false); }); let atLeast2NumbersGreaterThan5 = promises => anyNPromises(promises, a => a > 5, 2); atLeast2NumbersGreaterThan5([ Promise.resolve(5), Promise.resolve(3), Promise.resolve(10), Promise.resolve(11)] ).then(a => console.log('5, 3, 10, 11', a)); // true atLeast2NumbersGreaterThan5([ Promise.resolve(5), Promise.resolve(3), Promise.resolve(10), Promise.resolve(-43)] ).then(a => console.log('5, 3, 10, -43', a)); // false atLeast2NumbersGreaterThan5([ Promise.resolve(5), Promise.resolve(3), new Promise(() => 'never resolved'), Promise.resolve(10), Promise.resolve(11)] ).then(a => console.log('5, 3, unresolved, 10, 11', a)); // true 

0
source

Source: https://habr.com/ru/post/1269374/


All Articles