6
votes

I'm facing an issue in regards to error handling with Promise.all

I would expect the following code to call the catch part of the chain when one of the getNetworkstuff() Promises fails. But instead it just calls the next then part and the Browser Console shows an uncaught Error.

Promise.all(
    [[getNetworkstuff(url1)],[getNetworkstuff(url2)]]
    //please note that the arrays within the array are larger in my application
    //otherwise I would just use one big array not arrays in arrays
)
.then(function(result){//Stuff worked})
.catch(function(err){//Stuff broke});

function getNetworkstuff(url){
    return new Promise(function(resolve,reject){//here will be awesome network code})
}

I can see that the promise has not fulfilled as the returned result array contains the appropriate rejected promise.

[[PromiseStatus]]: "rejected"
[[PromiseValue]]: Error: HTTP GET resulted in HTTP status code 404.

Can somebody tell me why catch is not called? (I know it is if I just have an Array of Promises in Promise.all() of which one rejects)

1
You have an array of arrays. You will most likely need to call Promise.all on each. - Ben Fortune
Promise.all takes an array of promises as it's argument, not an array of arrays - Jaromanda X
Actually, I tried arrays of arrays and it does work trough them dutifully - Baiteman
Yeah, as everybody says, the first thing to try will be to remove one of those array levels: Promise.all( [ getNetworkstuff(url1), getNetworkstuff(url2) ], ... - fray88
I'd love to get rid of one level of arrays but I have about 40 URLs from which I want to load Data. Therefore I have related information in the respective arrays. The MDN Page says that the parameter has to be "an iterable such as an array". An Array in an Array classifies as iterable, doesn't it? - Baiteman

1 Answers

2
votes

Look at your console

function getNetworkstuff(url) {
    return new Promise(function(resolve, reject) {
        setTimeout(function() {
            console.log('resolving', url);
            resolve(url);
        }, 5000);
    });
}
Promise.all([[getNetworkstuff('url1')],[getNetworkstuff('url2')]])
.then(function(result){
    console.log('It worked', result);
})
.catch(function(err){
    console.log('It failed', result);
});

Notice it outputs "It worked", 5 seconds BEFORE anything is resolved

Promise.all([getNetworkstuff('url1'), getNetworkstuff('url2')])
.then(function(result){
    console.log('It worked', result);
})
.catch(function(err){
    console.log('It failed', result);
});

Now compare without the array of array - notice the difference in what is logged next to It Worked in both cases

and finally, run this

function getNetworkstuff(url) {
    return new Promise(function(resolve, reject) {
        if(url == 'url1') {
            setTimeout(function() {
                console.log('resolving', url);
                resolve(url);
            }, 5000);
        }
        else {
            console.log('rejecting', url);
            reject(url);
        }
    });
}

Promise.all([getNetworkstuff('url1'), getNetworkstuff('url2')])
.then(function(result){
    console.log('It worked', result);
})
.catch(function(err){
    console.log('It failed', result);
});

Your followup question: how are they kicked of if not being recognized as promises

Can you see that the code below is of a similar pattern to what you are doing with your array of array of results of functions that may or may not return promises? Anyway, take away the promises and the then stuff ... and you've got this

function fn(s) {
    return s.toUpperCase();
}
function fn2(arr) {
    console.log(arr); // [["A"], ["B"]]
}
fn2([[fn('a')],[fn('b')]]);