Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Update progressbar in each loop

I have a progress bar that I update in a loop of many iterations.

https://jsfiddle.net/k29qy0do/32/ (open the console before you click the start button)

var progressbar = {};

$(function () {

    progressbar = {

        /** initial progress */
        progress: 0,

        /** maximum width of progressbar */
        progress_max: 0,

        /** The inner element of the progressbar (filled box). */
        $progress_bar: $('#progressbar'),

        /** Set the progressbar */
        set: function (num) {
            if (this.progress_max && num) {
                this.progress = num / this.progress_max * 100;
                console.log('percent: ' + this.progress + '% - ' + num + '/' + this.progress_max);

                this.$progress_bar.width(String(this.progress) + '%');
            }
        },

        fn_wrap: function (num) {
            setTimeout(function() {
                this.set(num);
            }, 0);
        }

    };

});


$('#start_button').on('click', function () {

    var iterations = 1000000000;

    progressbar.progress_max = iterations;

    var loop = function () {

        for (var i = 1; i <= iterations; i++) {

            if (iterations % i === 100) {

                progressbar.set(i); //only updates the progressbar in the last iteration

                //progressbar.fn_wrap(i); //even worse, since no output to the console is produced

            }
        }
    }

    //setTimeout(loop, 0);
    loop();

});

The console is updated iteratively as expected. However, the progressbar is not updating.

The problem is that the browser window seems to 'hang' until the loop finishes. Only the console is updated, not the progressbar.

I have tried to add the setTimeout, as suggested below, in several places. But that just makes things worse, because I then do not even get the console to output the progress while executing the loop.

like image 784
reggie Avatar asked Jun 22 '15 18:06

reggie


2 Answers

Okay, I found a solution in the answer to this question:

Javascript: How to update a progress bar in a 'for' loop

var i = 0;
(function loop() {
    i++;
    if (iterations % i === 100) {
        progressbar.set(i); //updates the progressbar, even in loop    
    }   
    if (i < iterations) {
        setTimeout(loop, 0);
    }
})();

My solution: https://jsfiddle.net/ccvs4rer/3/

like image 58
reggie Avatar answered Oct 06 '22 05:10

reggie


Lets break this down to steps

Step 1: Clean up HTML

Assuming the purpose of your question is to understand how to work the progress bar and not the styles or the labels (loading, please be patient, etc.). Lets just have the progress bar and the start button.

<div id='progressbar-outer' style="">
    <div id='progressbar' style=""></div>
</div>
<button id="start_button">Start</button>

Step 2: The Styles

Lets make the progress bar visible to the user

#progressbar-outer {
    height:2em;
    border:5px solid #000;
    width:15em;
}
#progressbar {
    width:0%;
    background-color:#F00;
    height:100%;
}

Step 3: Using setTimeout where it belongs

In your code, you have used setTimeout to set the value of your progress bar. However, the for loop is still active.

for (var i = 1; i <= iterations; i++) {

    if (iterations % i === 100) {

        progressbar.set(i); //only updates the progressbar in the last iteration

        //progressbar.fn_wrap(i); //even worse, since no output to the console is produced

        //setTimeout(function() {
        //  progressbar.set(i);
        //}, 0);

    }
}

The use of setTimeout does not affect the rest of the code. Hence, the UI was held hostage till the loop ended. Try the following code.

$('#start_button').on('click', function () {

    var iterations = 100;

    progressbar.progress_max = iterations;

    var loop = function (value) {
        progressbar.set(value);
        if (value < iterations) setTimeout(function () {
            loop(value + 1)
        }, 30);
        else $('#progressbar').css('background-color', '#0F0');
    }


    loop(1);

});

Preview

Try this fiddle: https://jsfiddle.net/Ljc3b6rn/4/

like image 42
Lordbalmon Avatar answered Oct 06 '22 06:10

Lordbalmon