Tacking the progress bar onto an array of $.ajax() calls within a Promise.all

FINAL UPDATE 25/06/20: After a thorough investigation, I discovered the root causes of why the progress bar was not functioning as intended. Firstly, dealing with $.ajax() proved to be cumbersome due to its lack of proper promise handling. To resolve this issue, I switched to using AXIOS for making the calls, which significantly improved the situation.

  1. It became evident that I was making numerous calls throughout the process. Initially, I believed that the initial calls were minimal and not affecting the loading time before the bar fills up. However, upon analyzing the network traffic, it turned out that the preparation call was actually the most time-consuming. As a workaround, I modified the progress bar to fill up twice: once for the "preparation call" and then again for the actual request calls.

I appreciate all the advice provided by others, as it guided me in identifying where I had gone wrong!


UPDATE 25/06/20: For those interested, here is a link to the complete function on Gist since it is too lengthy to include here: Function in Gist. Line 215 contains the addition of the $.ajax() calls to matchPromises, while line 274 depicts where Promise.allSettled(matchPromises) is called.


Implementing a functional progress bar has been quite challenging for me during this project. While I won't share the entire code due to its length, I will provide a summary.

The ajax calls are structured like this:

$.ajax({
    "url": myUrl,
    "method": "POST",
    "success": (data) => {
        doStuff
        // POINT A
     },
     "error": (data) => {
         doStuff
     }
})

These calls are stored in an array named matchPromises, and then I utilize

Promise.allSettled(matchPromises)
successfully.

The challenge lies in updating a progress bar to indicate the completion status of promises. At the beginning of the function, I define the following:

let currentProgress = 0;
let maxProgress = 0;

function displayProgress() {
    currentProgress++;
    let calculatedWidth = (currentProgress / maxProgress) * 100;
    $('#progressBar').width(`${calculatedWidth}%`);
    $('#progressBar').attr('aria-valuenow', currentProgress);
}

Right before calling

Promise.allSettled(matchPromises)
, I update maxProgress using matchPromises.length.

I attempted inserting displayProgress() within the success section of the $.ajax calls, but faced the issue of maxProgress always reverting to 0 each time it's triggered.

Various efforts were made to promisify the $.ajax calls by encapsulating them in a new Promise and adding .then(), yet this resulted in execution only after Promise.allSettled had completed its execution.

This dilemma has consumed hours of my time, experimenting with different approaches. Any assistance from knowledgeable individuals would be greatly appreciated, as I am at a loss for solutions.

Answer №1

As the code is not fully provided for your specific scenario, I have attempted to create a solution that may be helpful.

I trust that this resolves your issue or at least sparks some inspiration.

const getLongRunningPromise = (milliseconds, value) => {
    return new Promise((resolve) => {
        setTimeout(() => resolve(value), milliseconds)
    });
};

const promises = [getLongRunningPromise(5000, 'a'), getLongRunningPromise(1000, 'b')];

let doneCount = 0;
const overallCount = promises.length;

const handleProgress = (result) => {
    doneCount++;
    const percentageDone = doneCount/overallCount*100;
    console.log(`${percentageDone}% Done`);
    return result;
};

Promise.all(promises.map(p => p.then(handleProgress))).then((results) => console.log('results', results));

Answer №2

Suppose you have a function named foo(). You can implement it like this:

function foo() {
    let currentProgress = 0;
    let someArray = .......;
    let matchPromises = someArray.map(function(myUrl) {
        return $.ajax({
            'url': myUrl,
            'method': 'POST',
            'success': (data) => {
                // doStuff
             },
             'error': (jqXHR, textStatus, errorThrown) => {
                // doStuff
             }
        })
        .always(function() {
            displayProgress(++currentProgress, matchPromises.length);
        });
    });
    Promise.allSettled(matchPromises).then(...); 
}

function displayProgress(current, max) {
    let calculatedWidth = (current / max) * 100;
    $('#progressBar').width(`${calculatedWidth}%`).attr('aria-valuenow', current);
}

Therefore, currentProgress is an internal variable of foo(), and there's no need to assign maxProgress; it's simply matchPromises.length.

If displayProgress() is not used elsewhere, it could also be defined within foo() or the two lines of code inside the .always() callback.

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

Unresolved promise: Internal server issue

I encountered an exception while working on my Nativescript app. EXCEPTION: Uncaught (in promise): Server error JS: ORIGINAL STACKTRACE: JS: Error: Uncaught (in promise): Server error JS: at resolvePromise (/data/data/com.yourdomain.appname/files/app/ ...

Please submit the form to log in with your credentials

Here is the HTML code snippet for a form where users can enter their username and password to log in: <form Name ="form1" Method ="POST" ACTION = "userlogin.php" id="form1"> <div id="main_body" class="full-width"> <label>User ...

Connect the scroll wheel and then proceed to scroll in the usual way

There are two div elements with a height and width of 100%. One has the CSS property top:0px, while the other has top 100%. I have implemented an animation that triggers when the mousewheel is used to scroll from one div to the other. The animation functi ...

Display only specific PHP-encoded JSON data in a formatted table

After receiving a variable from PHP, I convert it to JSON as shown below: var myData = <?php echo json_encode($json_array) ?>; When I log the output, it looks something like this: 0: Carat: "0.70" Clarity: "VVS2" Color: "D" Cut: "Very Good" Polish ...

Verify if any choices are available before displaying the div block

I need to determine if there is a specific option selected in a dropdown menu, and then display a div if the option exists, otherwise hide it. I'm not just checking the currently selected option, but all available options. if (jQuery(".sd select opti ...

Exploring the power of Typescript functions within a traditional VueJS project

TL;DR: How can I import and use a typescript module into my plain js Vue-Components? I have a Vue 2 (not yet 3) project. In this specific project, I have made the decision to refactor some of the code logic into ES modules for improved testability and reu ...

The render() method in a class does not support Jquery functionality, unlike the componentDidMount() method where it works effectively

After updating my packages to the latest versions, I encountered an error in my project. Previously, everything was working fine, but after upgrading Next.js to version 9 and jQuery to version 3.5, the $.map function stopped working as expected. When I tri ...

NodeJS controller function to generate and send a response

I'm facing an issue with my controller method where I am unable to send a response to the user, even though the value is displaying in the console. Below is my code snippet: const hubHome = (req,res) => { const hubId = req.params.hubId; fetch ...

Verify whether the element retains the mouseenter event after a specified delay

I recently implemented some blocks with a mouseenter and mouseleave event. <button onMouseEnter={this.MouseEnter}>hover</button> MouseEnter(e) { setTimeout(() => { // Checking if the mouse is still on this element // Pe ...

"Encountered a TypeError: Cannot read property 'params

I've encountered an issue with passing the id to my product page. Despite trying various solutions and searching for answers, I still can't get it to work. Below is my index.js code: import React from "react"; import {render} from &quo ...

Displaying the format when entering a value with react-number-format

How to Display Format Only After Full Value Inserted in react-number-format I recently implemented the react-number-format package for formatting phone numbers. import { PatternFormat } from 'react-number-format'; <PatternFormat value={v ...

Leveraging generics within TypeScript

I have developed a class in TypeScript that uses generics. export class ModelTransformer { static hostelTransformer: HostelTransformer; static fromAtoB(instance: T): U { if (instance instanceof HostelType) { return ModelTrans ...

What is the technique for performing asynchronous querying of multiple SQL databases?

Currently, I am in the process of developing a web application using nestjs and typeorm. I have been contemplating the functionality of the following code: const r1 = await this.connection.query(sqlA) const r2 = await this.connection query(sqlB) Does th ...

Building a custom HTML and JavaScript player to showcase multiple videos on a webpage

UPDATE: The solution has been discovered, shared, and marked as the top answer below. In the process of creating my portfolio website using HTML, CSS, and JS, I encountered a challenge regarding the addition of multiple videos on various pages. While fol ...

Deactivate filtering for the column in the header, while retaining it in the toolbar

I am currently working on implementing a jqGrid table. https://i.stack.imgur.com/d80M8.png My goal is to disable the filter functionality from the header column, while keeping it in the filter toolbar. Is there a way to deactivate the ui-search-input fo ...

What is the best way to transfer data between functions?

I'm working on a fun Santa's game to play with my friends. The concept is simple: you enter your name, click a button, and a random name from the list will be displayed as the result. I've encountered a couple of challenges: I can succe ...

Implementing dynamic components in Vuejs by passing props from objects

I have developed a dashboard application that allows users to customize their dashboard by adding widgets in any order. While the functionality is working fine, I am looking to address some technical debt and clean up the code. Let's simplify things ...

The perplexing simplicity of closure

Currently, I am endeavoring to enhance my knowledge of JavaScript closures. Let's consider the following two scenarios in Node.js: function A(){ console.log(data); //this will result in a null pointer } module.exports = function(data){ re ...

Best practice for incorporating Bootstrap into Webpack

Greetings everyone, I've been experimenting with Bootstrap for Webpack, but I've hit a roadblock. After reading numerous blog articles, I found that they either rely on the outdated 'bootstrap-webpack' plugin from 7 months ago (which d ...

Incorporating the non-typescript npm package "pondjs" into Meteor applications using typescript files

Implementing the Pondjs library into my project seemed straightforward at first: meteor npm install --save pondjs However, I'm encountering difficulties when trying to integrate it with my Typescript files. The documentation suggests: In order ...