skip to Main Content

FINAL UPDATE 25/06/20: Okay, so there were multiple reasons this was not working.

  1. $.ajax() is a pain to work with as it doesn’t really return proper promises. So any implementations relying on that didn’t work. Solution to this part was to change over to using AXIOS for the calls.
  2. I’m actually making a lot of calls during this process. I initially thought that the first set of calls I was making was small, and didn’t cause a lot of the loading time before the bar fills up. I was expecting the second set of calls to take a long time, and thus only coded the progress bar to take that into consideration. After analysing the network traffic, it turns out it was the complete reverse. So my solution was to actually have the progress bar fill up twice: once for the "preparation call" (which actually take the longest), and then fills up again on response of the actual request calls.

Thanks to all that gave their advice, it helped once I figured out where I was going wrong!


UPDATE 25/06/20: Here is a link to the Gist with the entire function as it is too big to post here: Function in Gist. Line 215 is where I add the $.ajax() calls to matchPromises. Line 274 is where I call Promise.allSettled(matchPromises)


I am having a lot of issues trying to get a working progress bar for this. I’m not going to post my actual code as it’s way too long, but I’ll post the gist of it.

The ajax calls are something like this:

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

I push them into an array called matchPromises and then I call Promise.allSettled(matchPromises) on that. This all works fine.

The problem I’m having is trying to update a progress bar to indicate how many promises are done. I have the following at the top of the function where I am doing everything else:

let currentProgress = 0;
let maxProgress = 0;

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

I update the maxProgress right before I call Promise.allSettled(matchPromises) by using matchPromises.length.

I have tried placing displayProgress() in the success part of the $.ajax calls – but the issue with that is that maxProgress will always stay at 0 every time it’s called.

I’ve tried a ton of various methods of promisifying the $.ajax by wrapping it in a new Promise and adding .then() – and this correctly reads maxProgress – BUT no matter which method I’ve tried, it only calls this in a huge block AFTER the Promise.allSettled has finished.

I’ve been at this for hours and have tried so many different methods. Really hope someone out there can help me with this because I’m at the end of my tether.

2

Answers


  1. Since there is some code lacking to apply that to your situation, I tried to sketch a helpful solution anyway.

    I hope this solves your issue or at least gives you 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));
    Login or Signup to reply.
  2. Assuming you have a function foo(), you can write something 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(...); // what happens here has nothing to do with displaying progress.
    }
    
    function displayProgress(current, max) {
        let calculatedWidth = (current / max) * 100;
        $('#progressBar').width(`${calculatedWidth}%`).attr('aria-valuenow', current);
    }
    

    Thus, currentProgress is an inner member of foo() and maxProgress never needs to be assigned – it’s just matchPromises.length.

    If it’s not called elsewhere, displayProgress() could also be an inner member of foo(), or just move the two lines of code inside the .always() callback (and adapt accordingly).

    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search