Nested loop combining Callback and Promise with two API requests

I apologize for the lackluster title, but I couldn't come up with anything more suitable. If this issue has already been addressed, please let me know in the comments and I will delete it promptly. However, keep in mind that this is a specific question.

Explanation: There is an API call that retrieves data from the server (an array) which then initiates a loop. Within this loop, another API call based on the parent index (child makes API call using parent index) fetches data and maps it into an array. A callback needs to be called after the last child of the last parent completes its task.


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');

Desired outcome

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

Actual 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=> {
                global_array.push(...);
                console.log('hello');
            });
        });
    });

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

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


What I've attempted 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=> {
                global_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=> {
                global_array.push(...);
                console.log('hello');
            });
        });
    })) });

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

Plus, some additional attempts. Any typos in the above codes are insignificant because they were written in the SO editor, so there may be missing parentheses/curly braces. Further information: No errors have been encountered. If you believe there are better solutions aside from promises (such as async/await...), please feel free to share your insights.

Answer №1

Your initial attempt was close; however, do not forget to ensure you return the promises from your callbacks. This way, functions such as then or Promise.all can properly wait for them:

projects.then(function(response){
    return Promise.all(response.projects.map(_e => {
//  ^^^^^^
        var project = api.getProjectContent(_e.id);
        return project.then(function(_response) {
//      ^^^^^^
            return _response.content.map(e=> {
//          ^^^^^^
                console.log('hello');
                return ...;
//              ^^^^^^
            });
        });
    }));
}).then(array_of_arrays => {
//      ^^^^^^^^^^^^^^^ results are obtained here
    // You may flatten this then() call
    console.log('yellow');
});

Answer №2

You were close to the correct solution with your initial attempt at using Promise.all. However, the function inside it failed to return the promise it generated, resulting in calling Promise.all on an array of undefined values.

To rectify this issue, consider adding a return statement like so:

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'); });
});

I also recommend utilizing forEach instead of Array.map when you are not generating new arrays. This way, your code's purpose will be clearer as map is intended for creating new arrays while forEach simply iterates through elements.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Sequentially loading Bootstrap columns as the page loads

Is there a way to load columns one by one with a time gap when the page is loaded? Here's the code snippet that can achieve this: setTimeout(function() { $("#box1").removeClass("noDisplay"); },1000); setTimeout(function() { ...

Managing Asynchronous Operations in Vuex

Attempting to utilize Vue's Async Actions for an API call is causing a delay in data retrieval. When the action is called, the method proceeds without waiting for the data to return, resulting in undefined values for this.lapNumber on the initial call ...

Adjustable height within embedded object tag

I've been struggling to adjust the height of the content on my site automatically. I have attempted using iframes as well, but nothing seems to work despite trying numerous code examples from various sources including CSS and JS scripts. Any help wou ...

Creating a Flot Bar Chart that displays non-stacking values

I am new to using Flot for creating charts. Currently, I have a bar chart displayed below: https://i.stack.imgur.com/RSumf.png Here is the code snippet I utilized to generate this chart: $.getJSON('chartBar.json', function(graphDataBar){ $ ...

The JSON array data is coming back as undefined

Currently facing an issue with the data sa var data = '[{"idcoupons_tbl":"1","discount_percent":"10"}]'; Every time I attempt to parse and retrieve a discount_percent, ie var result= jQuery.parseJSON(data); alert(result["discount_percent"]); ...

ng-if not functioning properly following the activation of the "Save Changes" button

When I click the edit change button, I am updating information and then hiding the form to show the updated details by clicking on the Save Changes button. My API successfully updates the information, but for some reason, ng-if does not seem to work afte ...

Click the button to instantly scroll to a particular word with highlighting, and with another click, jump to the next occurrence

In order to achieve the objective, simply click on a button that will search for and scroll to a specific word while highlighting it. The same button can be clicked again to find the next occurrence, and so on. If you need an example of how this works, ch ...

Vue instance with non-reactive data

I am looking to store an object in Vue that will be accessible throughout the entire instance but does not need to be reactive. Typically, if I wanted it to be reactive, I would use 'data' like this: new Vue({ data: myObject }) However, since ...

Tips for implementing a default font on a website

I've incorporated a unique font into a specific section of my website design, but I'm aware that this particular font may not be available on most of my users' computers. Is there a method to apply this font to selected text without resortin ...

Guide on initializing a Redux toolkit state with an array of objects or local storage using TypeScript

Currently, I am attempting to set an initial state (items) to an array of objects or retrieve the same from localStorage. However, I am encountering the following error. Type 'number' is not assignable to type '{ id: string; price: number; ...

Exploring the CSS scale transformation alongside the Javascript offsetHeight attribute

After combining offsetHeight with scale transformation, I experienced a strange result. Below is my simple HTML code: <body> <div id="id01"> Some Text </div> <div id="id02" style="transform-origin: left top; transf ...

Having trouble accessing Vuex's getter property within a computed property

Can you help me troubleshoot an issue? When I call a getter inside a computed property, it is giving me the following error message: TS2339: Property 'dictionary' does not exist on type 'CreateComponentPublicInstance{}, {}, {}, {}, {}, Com ...

Beginner's guide to using Express: a step-by-step tutorial on making API requests from client-side JavaScript to

Currently, I am immersed in a Javascript project where I utilize the Nasa Mars Rover API and Immutable Js to creatively display images and information on my webpage. By harnessing the power of pure functions and functional programming, I maintain app state ...

Troubleshooting Django Templateview: Incorporating Bootstrap Popovers into HTML tables not functioning properly

https://i.stack.imgur.com/LXHJF.pngWhen loading this template, the HTML renders correctly and the table loads successfully. However, certain cells have special pop-over attributes that do not work after the HTML is loaded via an AJAX request on the same pa ...

Click on the print icon in the modal window

I have been working on a receipt generator for a client. The client can add payment receipts using the "Add" button, and upon submission, they have the option to convert it to PDF or print it. However, there seems to be an issue with printing as the text f ...

Next.js - NextAuth consistently delivers a successful status code every time

In my Next.js project, I am utilizing NextAuth. The issue I'm encountering is that NextAuth consistently returns a 200 status code and updates the session to authenticated, even when the username or password doesn't match. I've attempted thr ...

determining the quantity within a collection of items

Is there a way to determine the order of an element within a set when clicked? For example, if I click on the third element in a set, can I get it to display as three? Check out this jsfiddle example for reference: http://jsfiddle.net/vtt3d/ ...

Updating React state from another component - using useState

How can I efficiently update this state in React so that it changes when a specific button is clicked within the <FirstPage /> component? I'm struggling with finding the best approach to accomplish this. Any suggestions? const SignUp = () => ...

The properties of a JSON object are not explicitly defined

When I make an AJAX call, I receive a JSON object and log it using this code: console.log(response); This is the response that gets logged in the console: {"filename":"new.jpg","orientation":"vertical"} However, when I try to access the orientation pro ...

Tips for effectively using the JQuery animate function

Displayed below is my implementation of the jQuery animate method abstraction that works well. However, a challenge arises when trying to replace the hard-coded DOM element class in the function ani(){} with the 'this' keyword for versatility acr ...