Unexpected behavior observed when executing JavaScript Promise.all code

My current issue involves retrieving data from a mySQL DB by using the following code. Within the database, there are multiple tables including an Activity table with a channelId field, a Channel table with a userId field, and a User table with a userName field. The function

getAllProjectACtivities(user, project)
is responsible for returning a promise containing an array of Activity objects, each encompassing all fields from the Activity table. Additionally, the function findChannel(channelId) returns a promise containing a single Channel object with all associated fields, while the function findUser(userId) provides a promise for a single User object along with its respective table fields. These functions perform JSON Ajax requests to the database and have been individually verified as functioning correctly.

My objective is to retrieve a list of activities, obtain the channel for each activity, and then identify the user for each channel. Subsequently, I aim to construct a table consisting of two activity fields and one user field.

To achieve this, a three-phase process of DB access is required, yielding arrays of objects. The provided code snippet outlines this process:

$(document).ready(function(){    
    var projNum=1;
    var userNum=1;
    var globalActivityList; 
    $('#tableContainer').append('<table border="0" style="background-color: lightblue;"></table>');
    var table = $('#tableContainer').children();

    getUserProjectActivities(userNum, projNum)
        .then(function (activityList){
            table.append("<tr><th>Number</th><th>Description</th><th>Employee</th></tr>");
            globalActivityList = activityList;
            return Promise.all(activityList.map(function(activity){
                findChannel(activity.activityChannelId);
            }));
        })
        .then(function (channelList){
            alert(channelList.length);
            alert(channelList);
            return Promise.all(channelList.map(function(channel){
                findUser(channel.channelEmployeeId);
            }));
        })
        .then(function(userList){
            for (var i=0; i<userList.length; i++){
                var tableString="<tr>";
                tableString+="<td>"+globalActivityList[i].activitityId+"</td>";
                tableString+="<td>"+globalActivityList[i].activitityDescription+"</td>";
                tableString+="<td>"+userList[i].userName+"</td>";
                tableString+="</tr>";
                table.append(tableString);
            }
        })
});

The challenge arises when the second .then receives an array without any information, causing subsequent code execution failures. Any insights on how to resolve this would be greatly appreciated. Thank you.

Answer №1

In order for those callbacks to properly execute asynchronously, they must return a promise. Currently, your map functions are generating an array of undefined values that are then passed into Promise.all. To rectify this issue,

return Promise.all(activityList.map(function(activity){
    return findChannel(activity.activityChannelId);
//  ^^^^^^
}));

and

return Promise.all(channelList.map(function(channel){
    return findUser(channel.channelEmployeeId);
//  ^^^^^^
}));

It's worth noting that perhaps using a single promise would be more efficient than having a globalActivityList. For each activity, consider creating an object that combines the channel and user information. This way, you can streamline the promises in a chain:

getUserProjectActivities(userNum, projNum)
  .then(function(activityList) {
      table.append("<tr><th>Number</th><th>Description</th><th>Employee</th></tr>");
      return Promise.all(activityList.map(function(activity) 
          return findChannel(activity.activityChannelId);
            .then(function(channel) {
                return findUser(channel.channelEmployeeId);
            })
            .then(function(user) {
                // Potentially unnecessary intermediate object
                return {activity:activity.activityID, description:activity.activityDescription, user:user.userName};
            })
            .then(function(item) {
                var tableString="<tr>";
                tableString+="<td>"+item.activitity+"</td>";
                tableString+="<td>"+item.description+"</td>";
                tableString+="<td>"+item.user+"</td>";
                tableString+="</tr>";
                return tableString;
            });
      }));
  })
  .then(function (list) {
      for (var i=0; i<list.length; i++){
          table.append(list[i]);
      }
  });

Answer №2

The issue lies in the way you are utilizing the .map function. It is essential for the callback within .map to return a value.

.all necessitates an array of promises, yet that is not what you are providing because of the incorrect usage of .map.

The intended usage of Promise.all(arr.map(...)) is to transform the array into a series of promises. Without returning a value from the .map callback, you fail to meet the expectations of .all.

I assume you meant to include return findUser(...); and return findChannel(...); (assuming they yield promises).

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

Creating a custom dialog box using JavaScript

How can I create a customized dialog box in the center without displaying "the host name says..." using CSS? function myFunction() { alert("Record Save"); } Thank you in advance! ...

What is the best way to disable the button hover effect after it has been clicked?

Many posts I've come across have similar issues to mine, but the suggested solutions are not working for me. I am struggling to remove the hover property of my button when it is clicked before triggering the removal event I have set up. Edit: Just t ...

TypeAhead.js and Bloodhound displaying an uneven quantity of search outcomes

I have a frontend setup with TypeAhead and Bloodhound integration, fetching JSON data from a Play/Scala server. The version of Typeahead being used is 0.11.1. Here is how the implementation looks: HTML: <div id="typeahead" class="col-md-8"> < ...

Invoke a MVC function from a web page using JavaScript

Currently, I am working with an ASP.NET MVC application and have the following Ajax call on one of the pages: $.ajax({ url: "/Home/GetAuthCode/", type: "GET", contentType: 'application/json', success: function () ...

Is there a way to alter the appearance of an HTML element without an ID using a JavaScript function?

I have a specific goal in mind, but I'm struggling to articulate it concisely. Despite conducting extensive research, none of the suggested solutions seem applicable in my case. Objective: I aim to change the background color of a div based on the da ...

AngularJS - Sending event to a specific controller

I am facing an issue with my page where a list of Leads each have specific actions that are represented by forms. These forms can be displayed multiple times on the same page. Each form has its own scope and controller instance. After submitting a form, an ...

What is the process to retrieve a variable from a Node.js file in an HTML document?

What is the best way to showcase a variable from a node.js route in an HTML File? I have a node.js route structure as follows: router.post("/login", async (req,res) => { try { const formData = req.body const name = formData.name ...

What could be the reason for my failing express test?

I'm in the process of configuring a server using Node/Express and I want to write ES6 code, so I've incorporated babel into my setup. Currently, the server is operational, and I can successfully make the necessary requests. However, I am facing ...

There was an issue encountered while parsing the JSON data - "SyntaxError: Unexpected token . was caught."

Encountering an error in Chrome while parsing JSON data. The JSON sample can be found at this link. It is valid JSON and the server is sending the correct Content-Type value (application/json). Uncaught SyntaxError: Unexpected token . Firefox shows a sli ...

Replacing values in an HTML file with MySql query results

----- Problem solved, solution below ----- In my HTML file, I have a dropdown menu for various courses listed as follows: <ul> <li class="dropbtn" id="1"> <a href="">first</a> <ul class="dropdown-content"> ...

Guide to incorporating PHP code into JavaScript

Encountering an issue when trying to combine PHP syntax within JavaScript syntax. var id = $("#data-1").val(); var url = '<?= base_url('home/alone/'); ?>'id''; console.log(url); I am trying to append the id at ...

I am uncertain about using double pointers as parameters in a swap function

Looking for some help! I implemented a shuffle function in my array.c file to shuffle the array elements. It's working with static Item *a; static int dim; in my array.c. static Item *a; static int dim = 3; a = malloc(dim * sizeof(Item)); void ran ...

Fill the second dropdown menu options based on the selection made in the first dropdown menu

I need assistance with dynamically populating my second drop-down menu based on the selection made in the first drop-down. Here are the steps I've taken so far: form.php - Utilizing javascript, I have set up a function to call getgeneral.php. The se ...

What is the best way to toggle the visibility of a side navigation panel using AngularJS?

For my project, I utilized ng-include to insert HTML content. Within the included HTML, there is a side navigation panel that I only want to display in one specific HTML file and not in another. How can I achieve this? This is what I included: <div ng ...

Can you suggest a more efficient approach to optimizing these angular bindings?

I integrated a form into a view within my Angular JS 1.2.6 application. <div class="container" ng-controller="LoginCtrl as signin"> <div class="row"> <div class="col-md-4"> <form name="signin.myForm" novalidate autocomplete="off" ...

Ways to exchange information among Vue components?

My role does not involve JavaScript development; instead, I focus on connecting the APIs I've created to front-end code written in Vue.js by a third party. Currently, I am struggling to determine the hierarchy between parent and child elements when ac ...

Transfer data from a MySQL table into a PHP array and send it to an AJAX request

I am attempting to retrieve values from a standard table using the traditional mysql_query and mysql_fetch_array methods through an ajax call in php if ($comtype==3){ $getsteps = mysql_query("SELECT id FROM steps WHERE id = $id"); $row = ...

Effortlessly navigate between Formik Fields with automated tabbing

I have a component that validates a 4 digit phone code. It functions well and has a good appearance. However, I am struggling with the inability to autotab between numbers. Currently, I have to manually navigate to each input field and enter the number. Is ...

PHP - Extract Information from Table Upon Form Submission without User Input

I'm facing a challenge with my web form that includes a table allowing users to delete rows before submitting. Although there are no input fields in the table, I need to capture the data from these rows when the form is submitted. The issue is that th ...

Removing custom scrollbars using jQuery from an element

Utilizing mCustomScrollbar with jQuery UI dialog boxes. When attempting to initialize mCsutomScrollbar on $(window).load as instructed, it fails because the dialogs are not yet visible. As a workaround, I've had to initiate mCsutomScrollbar on the op ...