Is it possible to transform this nested promise into a chain instead?

This situation is just a scenario

           | then (items)          | then (items, actions)
getItems() | getActions(for:items) | apply(actions -> items)
 :promise  |  :promise             | model <= items
           |                       |  :synchronous

In simpler terms:

  1. I have to retrieve a list of global items.
  2. Okay. Items retrieved.
  3. Request for actions taken on the items fetched previously by the user.
  4. Alright. Actions received.
  5. Apply actions to the items list.
  6. Add items to the model and show in view.

This is more or less what my code looks like

return itemsResource
       .getItems(userId)
       .$promise
       .then(function(items) {
           return actionsResource
                  .getActions(items.map(i => i.id)) // pseudo mapper code here
                  .$promise
                  .then(function(actions) { // THIS IS NESTED so it sees both promise results
                      return [items, actions];
                  });
       })
       .then(helper.spread(function(items, actions) {
           applyActions(items, actions);
           $scope.model.items = items;
           return items;
       }));

You can see that I cannot use $q.all initially because the second (actions) promise relies on the results of the first one (items).

Why not include actions with items? Because I'm caching items for all users, making item fetching quick. This is similar to how Stackoverflow operates. They provide questions regardless of who requests them. Later, they request preferred and ignored tags to apply to the fetched questions. This system scales efficiently, saving on server resources as every user's request would be different otherwise.

Why not display items in $scope right after fetching? This would remove the additional nested then, but I refrain from doing so since there are more steps to follow. Each time a promise resolves, at least one $digest cycle is executed. With many complex items, this processing can add up. Hence, I delay passing items to the view until absolutely necessary.

Query

Is there a way to eliminate the nested then without resorting to these two alternatives:

  1. Show items in $scope as soon as possible
  2. Save items locally for later use

I aim to simplify my code while minimizing additional resources, if possible?

Answer №1

It seems like this solution should be quite simple, right?

(I've made some adjustments to the internal function signatures for better clarity)

itemsResource.retrieveItems(userId)
  .then(function(items) {
    return $q.all({
      items: items,
      actions: actionResource.fetchActions(items)
    });
  })
  .then(function(data) {
    applyActions(data.items, data.actions);
    $scope.model.items = data.items;
    return data.items;
  });

Check out the plunker for a visual representation.

Answer №2

One potential solution could involve encapsulating the results from the items->actions chain within a promise. This approach might look something like this:

return $q(function(resolve, reject) {

    var outerItems;

    itemsResource.getItems(userId).$promise
        .then(getActions)
        .then(function (actions) {
            resolve([outerItems, actions]);
        })
        .catch(function (err) { reject(err); });

    function getActions(items) {
        outerItems = items;
        return actionsResource.getActions(items).$promise
    }

}).then(function (itemsAndActions) {
    var items = itemsAndActions[0], 
        actions = itemsAndActions[1];

    return helper.spread(function (items, actions) {
        applyActions(items, actions);
        $scope.model.items = items;
        return items;
    })
});

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

How to Assign a Specific ID to the Body Tag in Wordpress Using functions.php

Struggling to find a simple solution after scouring the web for answers. Most tutorials are overly complicated. I'm attempting to integrate a jQuery menu system into my Wordpress site and want to assign a unique body ID to make targeting easier. I p ...

Navigation bar failing to show all content on Safari web browser

When navigating to this website, http://www.togethermutualinsurance.co.uk, using any browser except for Safari on Windows, the menu displays correctly. However, in Safari, the title of the menus and submenus with images does not display properly. Despite ...

What is the best method for dividing a user interface into several arrays of keys, each grouped by type?

Given a simple structure: structure IPerson { firstName: string; lastName: string; age: number; city: string; favoriteNumber: number; isMarried: boolean; hasDriverLicense: boolean; } How do I create arrays containing keys grouped by data typ ...

Rails Navigation Issue: JQuery Confirmation Not Functioning Properly

Having a Rails app, I wanted to replicate the onunload effect to prompt before leaving changes. During my search, I came across Are You Sure?. After implementing it on a form, I noticed that it only works on page refreshes and not on links that take you a ...

``I am experiencing an issue with HttpXMLRequest becoming un

I am currently experimenting with the HttpXMLRequest object in JS and have created a basic loop that retrieves name and age data from an XML file to display in a table. The issue I am facing is that if one of the elements is missing from a sibling, the cod ...

Why isn't my textarea in jQUERY updating as I type?

On my website, I have a comment script that is not functioning correctly in some parts of the jQuery/JavaScript code. Instead of posting an edited comment to PHP, I created a notification window to test if the value passed through is actually changing. W ...

Tips for customizing the IconButton appearance in material-ui

While Material-ui offers a default icon button, I am interested in customizing its design to resemble this: IconButton design needed Could you please advise me on how to make this change? Thank you. ...

"Using Sequelize's Op.and and Op.like operators led to an unexpected outcome of producing an empty

I am working on developing a search endpoint using express and sequelize. I noticed an issue where using Op.and in my 'where' object results in an empty object: const where = { [Op.and]: req.query.q.split(" ").map((q) => { ...

Improving the functionality of a dynamic Mongoose JS application

Hey there, I have a pretty simple question that I couldn't find an answer to on Google. So, I'm experimenting with Mongoose JS and I'm curious about how to update a live application. Let's say I've defined a schema in my node.js ...

What is the reason behind utilizing the external 'this' within the inner function in Vue: $this=this?

Recently, I came across some code online that included a line $this=this. My initial interpretation was that this line assigns the 'this' of the outer function to a variable, allowing it to be used in the inner function as well. However, upon fur ...

My Node/Express application is failing to recognize updates made to my Pug view files

I have a Node/Express app that utilizes the Pug/jade template engine, and I am able to render everything successfully. However, I am facing an issue where modifications made to my index.pug file do not reflect on the homepage, even after restarting the ser ...

Using template expressions to access properties that contain spaces

Here is the code structure that I am working with: "name": { "age": [ { "data": { "how old": "23" } }, One of my JSON keys has a space in it. How can I access this pr ...

Counting the number of PHP inputs in a field

Hello, I am using a PHP script from Steve Dawson's website. To display the output on my HTML page, I am utilizing this AJAX script: <script> $.ajax({ type:'GET', url:'http://www.solariserat.se/count.php', data: ...

Using NodeJS to store the value from a callback function in a variable external to the function

I am facing a situation where I need to assign the value inside a callback function to a variable outside of it. Below is an example using child_process. callback.js let result; require('child_process').spawn('python', ['./hello.py ...

Create a custom CSS style to replace the default jQuery hide() function

HTML <div class="adm-input" <?php if(!empty($admin_fee) || $admin_fee != "") echo "style='display:block'"; ?> id="fees-input"> <label>Admission Fees(<i class="fa fa-inr"></i>)</label> <div class="in ...

Ways to display the hidden element using AngularJS

I want to show the information of "[6] Peter who is 95 years old" in a hidden text box, which should only appear when the button <button ng-click="show_id(friend.id)">get my id</button> is clicked. The name should be displayed using the ng-mode ...

The Node.js application is up and running on the Node server, but unfortunately, no output is

Greetings, I am a beginner in nodejs. var io = require('socket.io').listen(server); users = []; connections = []; server.listen(process.env.PORT || 3000); console.log('server running....on Pro'); app.get ('/', function(re ...

Sorting function not working on dynamic Angular table

I'm currently facing a challenge with sorting a dynamic Angular table. If I manually code the table headers, everything works smoothly. Fiddle: https://jsfiddle.net/xgL15jnf/ <thead> <tr> <td> <a href="#" ...

What could be causing the child view to not display the AJAX result?

An AJAX call is being made in the following manner: @Ajax.ActionLink("My Schedule", "GetSchedule", "Schedule", new { selectedDate = strToday}, new AjaxOptions { UpdateTargetId = "theTimes", InsertionMode = InsertionMode.Replace, HttpMethod = "GET" }) Th ...

Most effective method for displaying 100 images on a single page?

I have a webpage on my site that displays 100 images, but loading them one at a time makes it look unattractive. Is there a way to make it more elegant and visually appealing? ...