Creating promises from asynchronous tree-structured APIs in AngularJS can be achieved by following these steps

Dealing with Recursive Promises in a Hierarchical Data Structure

I am facing flow-control challenges within my application. I am working with a nested data structure that resembles a family tree, for example:

{name: "Bob", children: [{name: "Tim", children: [..]}, {another child..}]}

This structure can have multiple levels of depth.

My goal is to recursively traverse all individuals, obtain their ID, and make an API call to fetch their respective pictures.

Pseudo code snippet:

gatherPicture(hierarchy);
console.log("I want to wait before doing this!") // Logs too early
function gatherPicture(person) {
    // api request (promise)
    getPicture(person.id).then(r => {
        person.picture = r;
        person.children.forEach(gatherPicture);
    }) 
}

Hopefully, the provided code snippet clarifies things. How can I ensure that my code waits until the gatherPicture function has successfully processed and resolved all individuals?

If it helps, I am using AngularJS and have access to the $q promise service. However, I am unsure how to construct this specific chain of promises due to them being created within a recursive function.

Thank you!

Answer №1

In order to achieve success, it is crucial to utilize both $q.all and Array.prototype.map

gatherPicture(hierarchy)
.then(() => {
    console.log("I want to wait before doing this!")
})

function gatherPicture(person) {
    // execute API request (promise)
    return getPicture(person.id).then(r => {
        person.picture = r;
        return  $q.all(person.children.map(gatherPicture));
    }) 
}

Initially, ensure that you return the Promise chain initiated by getPicture within your gatherPicture function, in order to construct a reliable Promise chain.

Next, generate a collection of Promises for each child using

person.children.map(gatherPicture)
and then await resolution utilizing Promise.all

Answer №2

fetchImage = (user) => {
    loadImage(user.id)
    .then(result => {
        user.image = result;
        return Promise.all(user.friends.map(fetchImage));
    }) 
}

Answer №3

To optimize the process, one strategy is to initially flatten the tree structure:

const flattenTree = (tree) => (tree.children || [])
  .reduce((flattened, child) => flattened.concat(flattenTree(child)), [])
  .concat(tree);

Next, consider a basic function called fetchImage:

const fetchImage = (person) => retrieveImage(person.id).then((image) => {
  person.image = image;
});

Now, you can efficiently handle all tasks concurrently by awaiting their completion:

const fetchImages = (tree) => Promise.all(flattenTree(tree).map(fetchImage));

To implement this, use:

fetchImages(hierarchy).then(() => {
  console.log("Operation completed");
});

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

Is it necessary to have the script tag as the first tag in the body of the HTML?

I have a script file that needs to be included by third party implementors on their web pages. It is crucial for this script to be the first tag within the body element, like so: <body> <script type="text/javascript" src="/my_script.js"></ ...

What is the best way to restrict the input options for a String field within a TextField component in Material-UI?

When working with Material-UI, how can we set a maximum length restriction for a text field? Below you will find an example of the TextField component: <TextField id="name" label="Name" type="string" //maxLengt ...

Implementing Fullpage.js with persistent elements throughout slides

Can I keep certain elements fixed between slides? I found that the only way to accomplish this was by placing the text element outside of the slide div. <div class="section" id="section1"> <div class="intro"> <h1> ...

Click a button to dynamically create a div element with jQuery

Whenever I click the button to add an address, I want to dynamically create a new div structure using jQuery <div id="container"> <div class="address"> <div class="input-reg rb-item input-group"> <sp ...

When exporting a Mongoose model, it mysteriously becomes undefined

I am encountering an issue when trying to import the DemandeTransports model from a specific file: //@/components/database/model/Schema.js import { Schema } from "mongoose"; import mongoose from "mongoose"; const userSchema = new Schem ...

The current error received from navigator.geolocation.getCurrentPosition is "Position acquisition error: Unknown."

I am currently exploring the geolocation API in my project. After allowing my browser - whether it's on localhost or a web host - to access my location, I noticed that my console.log is displaying: Unknown error acquiring position I'm puzzle ...

Applying an active class in VueJs to a specific li element within a v-for loop when clicked

Struggling to select (set active class) in a v-for loop when one class is already selected. Here's the code and an explanation: These are my available subscriptions, with one already selected based on user data <ul> <li v-for="(s, key, ...

Integrating Illumination into a ShaderMaterial in three.js

I'm exploring the idea of creating a ShaderMaterial with lighting similar to that of a MeshLambertMaterial. To achieve this, I have developed a vertex and fragment shader (available here) and included the uniforms from THREE.ShaderLib[ 'lambert&a ...

Contrasting onevent with addEventListener

After studying various DOM events, I attempted to implement the 'blur' event on the HTML body. My first attempt was with onblur document.body.onblur = () => { dosomething(); } and I also tried using AddEventListener document.body.addEven ...

A single feature designed to handle various elements

I currently have this HTML code repeated multiple times on my webpage: <form class="new_comment"> <input accept="image/png,image/gif,image/jpeg" id="file" class="file_comment" key=comment_id type="file" name="comment[media]"> <spa ...

Logging Modal Toggle Clicks

I'm looking for a way to track views on my media catalog page, similar to an Instagram page. Each piece of media is displayed in a modal, and I want to have a "view count" recorded every time a modal is opened for that media. Here is a basic example ...

Failure to display updated property value

After rendering an array of objects, I am attempting to add a new property using a function. However, the new property value is not displaying on the page even though it is present when I log the object in the console. The new property that I want to add ...

The navigation bar's HTML hue

Currently working on a website design and looking to replicate the unique color gradient effect seen in the top navigation bar of Virgin America airlines' website (refer to the image linked below). Interested in any CSS/HTML techniques that could help ...

How can you determine the HTML element where a mouse click took place?

Is it possible in JavaScript to identify the HTML element where a mouse click occurs without having an event listener attached to the elements? Essentially, I want to be able to capture the mouse click event and determine the specific element on the page ...

Struggling to iterate through the children of a variable with the help of express-handlebars?

Currently, I am in the process of developing an application using Javascript along with express, express-handlebars, and MySQL. One of my main tasks is to establish a route that follows the pattern '/viewowner/:ID/scoreboards/:year' where ID sig ...

The passing of parameters from Angular to Web API during a POST request is not functioning properly

My Angular and Web API code seems to be passing null instead of "India" in the post method. Below is the snippet of my code: HWApp.controller('TestCtrl', function ($scope, $http) { $scope.SendData = function (Data) { $scope.wh ...

Navigating the landscape of asynchronous asset loading can present challenges. Attempting to access assets immediately may result in receiving

I have encountered an issue while trying to load my assets into an array using a function called LoadJSON(). This function utilizes THREE.ObjectLoader() to load JSON files. The problem arises when I attempt to access the members of the array immediately af ...

Having trouble transferring sound files to Cloudinary API through javascript

I have successfully implemented a function in my React Native application to upload images to Cloudinary. Now, I am trying to modify the function to upload audio files as well. Despite specifying the "resource_type" parameter as "raw", "video", or "auto", ...

Tips for ensuring that the click event function properly for numerous elements sharing the same class

I'm currently working on adding a flip effect to multiple tiles whenever a user clicks on them as part of building a dashboard-style webpage. I am having trouble making the click event work for all tiles with the same class name. Even though all the ...

Verify if the element is present before commencing any tasks

Looking for a solution: <div class="checkout-related-view__related-row"> <div class="checkout-related-view__related-row-cell checkout-related-view__related-row-cell--left"> <input type="checkbox" class="checkbox related-checkbox" id ...