Search code examples
javascriptecmascript-6es6-promise

Callback/Promise nested loop, 2 API calls


My apologies about the title I couldn't find anything better. if this problem has an answer already feel free to inform me in the comments below and ill delete it right away but keep it in mind this is not a general question.

Explanation: There is an API call that will fetch data from the server (an array) and then based on that array it will start a loop, inside the loop we have another API based on parent index (child make API call by using parent index) and get some data and map them into a variable (an array). I need to call a callback after the last child of the last parent done his job.


Mimic code:

for(let i=0;i<2;++i){
    for(let j=0;j<2;++j){
        map data into another array with predefined shape
        console.log(i +", "+ j)
    }
}
console.log('good to go for callback');

Desirable result

0, 0
0, 1
1, 0
1, 1
good to go for callback

Real code:

var projects = api.getProjects(req);

projects.then(function(response){
    response.projects.map(_e => {
        var project = api.getProjectContent(_e.id);
        project.then(function(_response){
            _response.content.map(e=> {
                a_globa_array.push(...);
                console.log('hello');
            });
        });
    });

    console.log('yellow');
});

I want to exactly after every single child from every single parent pushed into an array, print "yellow" in the console (or get the length of the array).


What I've tried so far:

var projects = api.getProjects(req);

projects.then(function(response){
    Promise.all(response.projects.map(_e => {
        var project = api.getProjectContent(_e.id);
        project.then(function(_response){
            _response.content.map(e=> {
                a_globa_array.push(...);
                console.log('hello');
            });
        });
    })).then(()=>{ console.log('yellow'); });
});

And

var projects = api.getProjects(req);

projects.then(function(response){
    let pr = new Promise((resolve, reject) => {response.projects.map(_e => {
        var project = api.getProjectContent(_e.id);
        project.then(function(_response){
            _response.content.map(e=> {
                a_globa_array.push(...);
                console.log('hello');
            });
        });
    })) });

    pr.then(()=>{ console.log('yellow'); });
});

And some more. Typo in above codes are not important because i wrote them in SO editor so maybe I missed some parentheses/curly braces. Additional info: There is no errors. If you think there is better solutions rather than promise (async/await ...) please let me know and share your thoughts.


Solution

  • You almost got it with the first Promise.all snippet, but the function inside it doesn't return the promise it created, so you're calling Promise.all on an array of undefined.

    Try this (same thing, with added return):

    var projects = api.getProjects(req);
    
    projects.then(function(response){
        Promise.all(response.projects.map(_e => {
            var project = api.getProjectContent(_e.id);
            return project.then(function(_response){
                _response.content.map(e=> {
                    a_globa_array.push(...);
                    console.log('hello');
                });
            });
        })).then(()=>{ console.log('yellow'); });
    });
    

    Also, I would suggest avoiding Array.map when you're not actually returning any values. Using forEach instead makes the intent clearer (map is used for creating a new array, while forEach is simply a loop).