Resolve a promise once all internal concurrent promises have resolved or rejected

959 Views Asked by At

I am looking for something similar to Promise.all that will continue to resolve promises concurrently even in the event that one or more of the promises reject or throw an error. Each request does not rely on another request.

Close to what I want - please see comments

function fetchRequest (request) {
  return new Promise(function (resolve, reject) {
    fetch(request)
    .then(function(response) {
      return response.text();      

    }).then(function (responseXML) {
      //Do something here. Maybe add data to dom
      resolve(responseXML);

    }).catch(function (err) {
      reject(new Error(err));
    }
}

function promiseRequests (requests) {
  var result = Promise.resolve();

  for (var i = 0; i < requests.length; i++) {
    result = fetchRequest(requests[i])
  }

  //This is wrong as it will resolve when the last promise in the requests array resolves
  // - not when all requests resolve
  resolve(result);
}

promiseRequests(['url1.com', 'url2.com']).then(function (data) {
  console.log('All requests finished');
  //optionally have data be an array of resolved and rejected promises
});

I have succeeding in using Promise.all together with only ever resolving the fetchRequest promise and this results in the expected outcome (an array of results and undefined's) but I feel like this is the wrong way to do things. It also removes my ability to use thrown errors.

Works but feels like incorrect use of resolve

function fetchRequest (request) {
  return new Promise(function (resolve, reject) {
    fetch(request)
    .then(function(response) {
      return response.text();      

    }).then(function (responseXML) {
      resolve(responseXML);

    }).catch(function (err) {
      resolve();
    }
}

Promise.all([fetchRequest('url1.com'), fetchRequest('url2.com')]).then(function (data) {
  console.log('All requests finished', data); //data could be ['resultXML', undefined]
});

Please only native es6 promise API answers thanks.

2

There are 2 best solutions below

8
On BEST ANSWER

I have succeeded in using Promise.all together with only ever resolving the fetchRequest promises

That's basically the way to go. ES6 does not have a helper function like allSettled (Q) or settle (Bluebird 2.x) for this case, so we will need to use Promise.all similar to like you did. Bluebird even has a dedicated .reflect() utility for this.

You would however not resolve them with undefined in the case of a rejection, but rather with some useful value that allows to identify the errors.

function promiseRequests(requests) {
  return Promise.all(requests.map(request => {
    return fetch(request).then(res => {
      return {value:res};
    }, err => {
      return {reason:err};
    });
  }));
}
0
On

You are essentially asking for a way to swallow any errors. As such, a function like this will be your best bet:

function swallow(p) {
  // transforms rejected promises into promises fulfilled with undefined
  return p.catch(function () { });
}

You would use it as follows:

Promise.all([swallow(fetch('url1.com')), swallow(fetch('url2.com'))]).then(function (data) {
  console.log('All requests finished', data); //data could be ['resultXML', undefined]
});

or even

 const promises = ['url1.com', 'url2.com'].map(fetch).map(swallow);
 Promise.all(promises).then(function (data) {
   // ...
 });