0

I have this array of Promises like:

let promisesArray = [
    service1.load('blabla'),
    service2.load(), // throws an errors
];

and I want to execute them all and catch their errors like this

Promise.all(promisesArray)
    .then(() => doStuffs())
    .catch((err) => handleError(err));

that's working fine but I now want to that in the then() of another promise:

baseService()
    .then(() => Promise.all([
        service1.load('blabla'),
        service2.load(), // throw an errors
    ]))
    .catch((err) => handleError(err));

this one's works also fine as long as I write the array directly in Promise.all(), but if I want to use promiseArray define earlier like:

baseService()
    .then(() => Promise.all(promisesArray))
    .catch((err) => handleError(err));

then, the catch() is run as expected but I have an error in the console

publish.js:45784 EXCEPTION: Error: Uncaught (in promise): ...

But I want to use that last solution as my array is generated according to some conditions by pushing the Promises to it. (and the first example is working just fine, I don't get what is different)

Adding catch to each of my promises while adding them to the array save my problem, but I'd like to find a better solution.

I would really appreciate some help with that.

PS: I am using angular2 with zone.js if it changes something

Thomas
  • 75
  • 2
  • 5
  • Please show us how you are creating `promisesArray`. Maybe have a look at [this](http://stackoverflow.com/q/37801654/1048572) – Bergi Jul 22 '16 at 13:31

3 Answers3

2

As soon as you execute an async function (one that returns a promise) it begins running the task in the background (kindof) that promise may resolve or reject at any time from the moment you run

let promisesArray = [
    service1.load('blabla'),
    service2.load(), // throws an errors
];

these services are going off and loading data, if they return before a .then() is attached, they will hold onto their value and as soon as you call promisesArray[0].then(x => console.log(x)) the then function will be run with that value

HOWEVER If one of these services throws an error and there is no .catch function attached yet, they will hold onto the error in order to send it to a .catch() function later specified, but they will also throw a console error - because they dont know if there will ever be a catch function attached, and it would be frustrating if promises just silently failed and errors disappeared.

If you truely want your promisesArray to execute AFTER baseService(), then your idea of making promisesArray an array of functions which kick off an async task and return a promise - is a good one. However it may be nicer to pass in a function which returns an array of promises, rather then passing in an array of functions which return promises (as stated above)

const getPromises = () => [
    service1.load('blabla'),
    service2.load(), // throws an errors
]

then execute using

baseService()
    .then(() => Promise.all(getPromises()))
    .catch((err) => handleError(err));

This will only start your service1.load's after baseServce() has completed, and all errors will be caught as soon as they occour

Jye Lewis
  • 678
  • 3
  • 16
0

Since you're using angular2, why not using Observable and Http.

var load1 = http.get('url1'),
    load2 = http.get('url2'),
    load3 = http.get('url3');

Observable.forkJoin(load1, load2, load2, function(res1, res2, res3){
    // manipulate your results here and return the reduced result

    return { whatever : { res1: res1, res2: res2, res3: res3 } }

}).
subscribe(function(finalResult){
     console.log(finalResult); // { whatever : { res1: res1, res2: res2, res3: res3 } }
});
Lance
  • 865
  • 8
  • 19
  • That would avoid my problem, but that will be quite some changes on my services. I'd rather fix it while keeping the Promises - and really I'd like to learn what is actually different between the last two examples. – Thomas Jul 22 '16 at 11:12
0

I figured out a way to make it work.

Instead of an array of promise I make an array of functions that return a Promise:

let promisesArray = [
    () => service1.load('blabla'),
    () => service2.load(), // throws an errors
];
promisesArray.push(() => service2.load())

Then I use Array.prototype.map() to run the promises in Promise.all():

baseService()
    .then(() => Promise.all(promisesArray.map(promise => promise())))
    .catch((err) => handleError(err));

That is solving my problem, not sure if it's the best way to do it though. If anyone have a better idea, i'll take it.

Thomas
  • 75
  • 2
  • 5
  • If that is a solution (I don't know the problem), at least don't call it `promisesArray` but rather `factoryArray` or `actionsArray` or `loadFns` or whatever fits. – Bergi Jul 22 '16 at 13:32
  • 1
    Alternatively, just declare a function that returns the array of promises, that's probably a better idea. – Bergi Jul 22 '16 at 13:34