David Tzoor
David Tzoor

Reputation: 1077

javascript - run promises in parallel but handle rejections separately

I use bluebird.js map function to perform parallel requests to an external API I use.
whenever any of the inner promises gets rejected, the map function also gets rejected (I know that this is by design).
I was wondering if there is any way to run promises in parallel but handle each rejection separately, and not fail the entire Promise.

Upvotes: 0

Views: 281

Answers (3)

Redu
Redu

Reputation: 26161

Without any library with pure ES6 promises you may have an approach like this. In this case the promiseAll function would honor resolved promises along with the rejected ones.

function promisify(fun){
  return (data) => new Promise((resolve,reject) => fun(data, (err,res) => err ? reject(err) : resolve(res)));
}

function async(data, callback){
  data.val+= " msec";
  Math.random() < 0.5 ? setTimeout(_ => callback(false,data.val),data.dur)
                      : setTimeout(_ => callback("error"),data.dur);
}

function myNormalCallback(resultObject){
  console.log("Promise " + resultObject.count + " returned " + resultObject.result);
}

function myErrorCallback(errorObject){
  console.log("Promise " + errorObject.count + " returned " + errorObject.error);
}

function promiseAll(proms){
  return new Promise((v,x) => { var results = new Array(proms.length).fill(void 0);
                                proms = proms.map((prom,i) => prom.then(res  => {results[i] = res;
                                                                                 results.indexOf(void 0) === -1 && v(results);
                                                                                })
                                                                  .catch(err => {results[i] = err;
                                                                                 results.indexOf(void 0) === -1 && v(results);
                                                                                }));
                              });
}

var datas = [{val: 100, dur: 1000},{val: 200, dur: 2000},{val: 300, dur: 3000}],
    proms = datas.map(data => promisify(async)(data));
promiseAll(proms).then(results => results.map((res,i) => res === "error" ? myErrorCallback({count:i,error: res})
                                                                         : myNormalCallback({count:i,result: res})));

Upvotes: -1

Bergi
Bergi

Reputation: 664548

I was wondering if there is any way to run promises in parallel but handle each rejection separately, and not fail the entire Promise.

Sure there is - just handle them using catch or error:

const all = Promise.map(somethings, function(something) {
    return doSomething(something).catch(function(e) {
        return handleIt(e); // normal completion, no rejection or exception
    });
});

See also Wait until all ES6 promises complete, even rejected promises in general.

Upvotes: 2

Benjamin Gruenbaum
Benjamin Gruenbaum

Reputation: 276306

I would use .reflect with the map to get promise inspections as the result:

const all = Promise.map(items, item => doSomething(item).reflect());

all.then(items => {
  // will contain an array of the promises that fulfilled correctly
  let fulfilled = items.filter(x => x.isFulfilled()).map(x => x.value()));
  // will contain an array of the promises that rejected 
  // so you can handle the errors
  let rejected = items.filter(x => x.isRejected()).map(x => x.reason());

});

Upvotes: 3

Related Questions