2

I had posted a question earlier about Promise.all and d3.js v5, but another question come up regarding this piece of code:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];

files.forEach(function(url) {
    promises.push(d3.json(url))
});

Promise.all(promises).then(function(values) {
    console.log(values)
});

If one of the URL's is invalid, the Promise.all doesn't return any of the results; in other words, all responses must be valid for the Promise.all to return the values. How can one get the other responses in the case of an error in one of the URL's?

Marco A. Ferra
  • 193
  • 1
  • 1
  • 7
  • You can use Observable to handle this because it has powerfull features like next, retry, etc ... With promise, if one request fail, the code excecution stop. But with Observable, if one request failed, other can be done – Radonirina Maminiaina Mar 28 '18 at 15:18

5 Answers5

2

That's how Promise.all works. But if you want to get it work for rejected promises, you can do it like this:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = [];

files.forEach(function(url) {
    promises.push(
      d3.json(url)
        .then(function(data) {
          return {success: true, data: data};
        }, function() {
          return {success: false};
        })
    )
});

Promise.all(promises).then(function(values) {
    console.log(values)
});

Note that Promise#then can accept two functions as arguments, first one is called when the promise is resolved, and the second one is called when its rejected.

You can manually resolve the rejected promise, and can return an identifier to know if the call resulted in success or failure, like I did using the success key.

31piy
  • 23,323
  • 6
  • 47
  • 67
1

Try to wrap each promise to your custom promise and resolve each of them.

Here is example:

const wrappedPromises = promises.map(promise => {
  if (promise) {
    return new Promise((resolve, reject) => {
      promise.then(resolve).catch(resolve);
    });
  }
});

Promise.all(wrappedPromises).then(function(values) {
  console.log(values)
});
Artem Mirchenko
  • 2,140
  • 1
  • 9
  • 21
1

You want something like Promise.settle. You can get that with Bluebird and .reflect(): http://bluebirdjs.com/docs/api/reflect.html

function settle (promises) {
  return Promise.all(promises.map(promise => promise.reflect()));
}


var x = [Promise.resolve(1), Promise.reject(new Error("omg")), Promise.resolve(2)];

settle(x).then(console.log)
<script src="//cdn.jsdelivr.net/bluebird/3.5.0/bluebird.js"></script>
ktilcu
  • 3,032
  • 1
  • 17
  • 15
1

With Promise.all you need to make sure that every Promise resolves (meaning that it doesn't reject). it's very easy to accomplish this, just handle rejection and recover from it. For example:

var files = ["data1.json", "data2.json", "data3.json"];
var promises = files.map(function(url) {
  return d3.json(url)
    .catch(function (err) {
      return {
        error: err
      }
    })
});

Promise.all(promises).then(function(values) {
  console.log(values)
});

So all you need to add is catch block:

.catch(function (err) {
  return {
    error: err
  }
}
dfsq
  • 191,768
  • 25
  • 236
  • 258
0

Write your own version of Promise.all. Keep track of resolved and rejected promises and return whatever array you see fit once all promises are either resolved or rejected.

H.B.
  • 166,899
  • 29
  • 327
  • 400