2

I have a list of items to be processed. Lets says A,B,C,D,E .. I have a list of promises which processes these items. Each promise can process 1 or more items. I have a list of items which need to be mandatorily processed.

Lets say A, C are mandatory items.

  • Promise 1 processes A,B
  • Promise 2 processes A,C
  • Promise 3 processes B,C.

I can return in any of the following cases

  1. P1,P2 are completed (don't care about P3)
  2. P1,P3 are completed (don't care about P2)
  3. P2,P3 are completed (don't care about P1)
  4. P1,P2,P3 are completed.

All promises (async calls) are started at the same item sequentially. How do I handle this with Promise of iterables.?

One way I could think of is

Promise.race(
    Promise.all(P1,P2),
    Promise.all(P1,P3),
    Promise.all(P2,P3),
    Promise.all(P1,P2,P3)
)

This should work. But this requires me to construct the list of promise combinations based on the mandatoryItems and eachPromiseItems.

Is there a proper elegant way to handle this case in JavaScript?

Patrick Roberts
  • 49,224
  • 10
  • 102
  • 153
Senthil Vidhiyakar
  • 182
  • 1
  • 2
  • 9
  • `Promise.race` will return the first promise to `fullfil` or `reject`. So, you might need some mechanism that will run all promises and tell you what was fulfilled and what was rejected. I can think of combining `.all`, `.race`, and this answer here https://stackoverflow.com/questions/31424561/wait-until-all-promises-complete-even-if-some-rejected – Mu-Majid Jul 19 '20 at 11:20
  • 1
    Do you mean you want to ignore a failure (rejection of the promise) for the non-mandatory items, or that you want to return *as soon as* the promises for all the mandatory items are fulfilled? – Bergi Jul 19 '20 at 11:42
  • Of all the combinations I want to return as soon as one combination of promises resolve. I am ok with other combinations taking time. But I definitely want to capture rejection of a combination. @Bergi – Senthil Vidhiyakar Jul 19 '20 at 12:18
  • 1
    @SenthilVidhiyakar Ok, so your code works, you really want `Promise.race` not `Promise.any` or `Promise.allSettled`. However I don't truly understand the example - if only items A and C are mandatory, and both are processed by promise P2, then wouldn't P2 alone be sufficient? And racing for `Promise.all(P1,P2,P3)` is useless, as the subsets will always resolve earlier than that anyway. – Bergi Jul 19 '20 at 12:32
  • What exactly do you mean by "*with Promise of iterables.*"? The solution "*requires me to construct the list of promise combinations based on the mandatoryItems and eachPromiseItems.*" - what is the problem with that? Are you asking how to construct that list dynamically? Then please share the input datastructures. – Bergi Jul 19 '20 at 12:34

2 Answers2

0

As an optional advice. You can create a promise wrapper to process all of your promises and resolve it whenever you want.

function afterPromises(yourPromiseList, checker) {
    var _P = new Promise((res, rej) => {
        for (var p of yourPromiseList) {
            p.then((data) => {
                let checked = checker(data);
                if(checked===true){
                    res()
                }
                if(checked===false){
                    rej()
                }
            })
        }
    })
    return _P;
}

afterPromises([...yourPromiseList], () => {
    var itemsDict = {}// a closure var to register which your items processed
    return (data) => {
        itemsDict[data.id]=true
        //And your extra logic code
        return true
        //or return false
        //or reutrn undefined
    }
}).then(()=>{
    //resolved
})

THE CODE NOT TESTED

lei li
  • 1,244
  • 1
  • 12
  • 35
0

I'm not sure that there is something built-in for this requirement but you can run over an array of promises and handle this logic like this:

const p1 = new Promise(resolve => {
  setTimeout(() => {resolve(['A','B']);}, 500);
});

const p2 = new Promise(resolve => {
  setTimeout(() => {resolve(['A','C']);}, 500);
});

const p3 = new Promise(resolve => {
  setTimeout(() => {resolve(['B','C']);}, 500);
});

const mandatory = ['A','C'];

function promisesRunTillMandatoryCompleted(promises, mandatory) {
    return new Promise((resolve, reject) => {
       let results = [];
       let completed = [];
       
       promises.forEach((promise, index) => {
            Promise.resolve(promise).then(result => {
                results[index] = result;
                completed = [...new Set(completed.concat(result))];
                
                if (mandatory.every(elem=> completed.indexOf(elem) > -1)) {
                    resolve(results);
                }
            }).catch(err => reject(err));
       });
    });
}

promisesRunTillMandatoryCompleted([p1,p2,p3],mandatory)
.then(() => console.log('all mandatory commpleted'));