2

I am nesting an Axios call in another in order to get the list of IDs from my first call and then loop through and for each ID get the status from a 2nd API call. It will only return the first status when I log the array, versus showing the full array.

I believe the issue may be in the promise chain... or if this is not waiting for the promises to complete before outputting the final array.

    var responsearray = [] 
    
    axios.get('https://myapi.net/api/role/allroles?pageSize=1000').then(function (response) {

    for(var i = 0; i < response.data.roles.length; i++)
    {
        var entry = response.data.roles[i];
        var entryid = entry.id;

        return axios.get('https://myapi.net/api/role/score/' + entryid).then(function (response2) {
               // Nested call per role to push to array
               responsearray.push(response2.status)
    });
    }

  }).catch(function (error) {
    // handle error
    console.log(error);

  }).then(function () {
    // always executed
        // Return Array
    console.log(responsearray);
  });
Kode
  • 3,073
  • 18
  • 74
  • 140
  • 2
    You're unconditionally returning in the middle of the `for` loop, of course it's only processing the first element – Tibrogargan Aug 13 '21 at 21:38

2 Answers2

1

It looks like the outer promise is being resolved since you are returning a value (which is the first inner promise, the first Axios call inside the loop).

Then, when the outer promise resolved, the outer then function is being called with the responsearray that happens to hold the result of the first response2 (however it might even be empty since the second Axios call may haven't been resolved yet).

So the flow is something like that:

First axios call => first Then is called => i=0, second axios call is **RETURNED** => first axios call is resolved => last then is called => (second axios may be resolved by now and responsearray is filled with the result for i=0) => console.log(responsearray)

Anyway, I would suggest using Promise.all that gives you a promise that contains a collection of promises and resolve it only if all of the promises are resolved. You can read more about it here.

I would use it something like that:

var responsearray = [] 
    
axios.get('https://myapi.net/api/role/allroles?pageSize=1000').then(function (response) {

    for(var i = 0; i < response.data.roles.length; i++)
    {
        var entry = response.data.roles[i];
        var entryid = entry.id;

        //pushing the promise into responsearray
        responsearray.push(axios.get('https://myapi.net/api/role/score/' + entryid).then(function (response2) {
              console.log(i + " resolved");
        }).catch(function (error) {
    // handle error
    console.log(error);
});
    })
    console.log("Done pushing all the promises");
    return responsearray;

}).catch(function (error) {
    // handle error
    console.log(error);
}).then(function (responsearray) {
    console.log("outer axios is resolved");
    // responsearray should have all the promises by now
    Promise.all(responsearray).then((results) => {
       console.log(results);
    }).catch(function (error) {
    // handle error
    console.log(error);
});
});
SomoKRoceS
  • 2,934
  • 2
  • 19
  • 30
  • Thanks, this is the right direction but it seems to be skipping the pushing to the array. The output ran as: "Done pushing all the promises" "outer axios is resolved" very quickly and never logged the i + resolved – Kode Aug 16 '21 at 21:19
  • 1
    The whole snippet is a part of a longer code, I'm assuming. So is there any chance the "bigger" program or the function call doesn't wait for the promise to be resolved? Try making this snipper synchronized and wrap the whole snippet with an async function and put an `await` before `Promise.all(res.....` – SomoKRoceS Aug 16 '21 at 21:28
  • There is just a call off a button click. Maybe some closure issues? Where you have the 2nd call I closed it with })); to close the push – Kode Aug 16 '21 at 21:36
  • Wait, it took a while for the promises to get returned so the individual console log in the loop worked, but now an error: UnhandledPromiseRejectionWarning: Unhandled promise rejection. This error originated either by throwing inside of an async function without a catch block, or by rejecting a promise which was not handled with .catch(). To terminate the node process on unhandled promise rejection, use the CLI flag `--unhandled-rejections=strict` (see https://nodejs.org/api/cli.html#cli_unhandled_rejections_mode). (rejection id: 2) – Kode Aug 16 '21 at 21:50
  • 1
    Yes. You should put a `catch` to the promises so the program won't get terminated. I'll edit that in my answer. However, some of the promises seems to get rejected, which you'll need to figure out why. – SomoKRoceS Aug 17 '21 at 15:58
  • 1
    Makes complete sense. I was testing that as well. Appreciate the assist. – Kode Aug 17 '21 at 17:21
1

If you know you're going to have a collection of Promises, use the methods that the Promise class gives you to handle that.

For example, you could use something like Promise.all() to handle an array:

var responsearray = [] 
        
axios.get('https://myapi.net/api/role/allroles?pageSize=1000').then(
    function (response) {
        for(var i = 0; i < response.data.roles.length; i++)
        {
            // get a single Promise and append it to our collection
            responsearray.push(axios.get('https://myapi.net/api/role/score/' + response.data.roles[i])
        }
    }
)
Promise.all(responsearray)
    .then( responses => responsearray = doSomethingWith(responses) )
    .catch(function (error) {
        // handle error
        console.log(error);
    })
    .then(function () {
        // always executed
        // Return Array
        console.log(responsearray);
    });

This may not suit your use case completely, since Promise.all() is all or nothing (see this). There are other options for this, like Promise.allSettled()

Tibrogargan
  • 4,508
  • 3
  • 19
  • 38
  • This makes complete sense and i what I suspected. Thanks for the clear answer per promises – Kode Aug 14 '21 at 15:51