2

How can I take a Javascript for loop display the number of times it has looped with a live count?

for (var i = 0; i < 10; i ++) {
    [ DO FUNCTION HERE ]
    document.getElementsByTagName("span")[3].innerHTML = "Cycles: " + i;
}

I want it to show "Cycles: #" and have the # increment live as it is looping through each function. Similar to a loading screen. Ideas?

Aaron
  • 1,956
  • 5
  • 34
  • 56
  • Did you try your code? How does it behave differently than you expect? In addition to describing what you want to happen, you should always state what actually happens. – outis Sep 15 '11 at 22:12
  • Yeah your code works fine when I test it. – daxnitro Sep 15 '11 at 22:15
  • My code works fine. I'm just looking for the numbers to change instead of showing "Cycle 10" immediately. – Aaron Sep 15 '11 at 22:17
  • 1
    i think he wants to see the live counter not the final result – Tarek Sep 15 '11 at 22:17
  • What I want to have happen is similar to when you're typing in the comment box and it shows how many characters are left, the counter changes LIVE. I want my "Cycles: #" text to change LIVE. – Aaron Sep 15 '11 at 22:17
  • If the code represented by `[DO FUNCTION HERE]` is synchronous, the sample code *is* showing the live count; it just happens so quickly that you don't see the lesser count values. If `[DO FUNCTION HERE]` represents asynchronous code, you'll need to implement [coordination](http://stackoverflow.com/questions/1483405/is-erlangs-recursive-functions-not-just-a-goto/1496088#1496088) yourself. A better description than you "want live counter changes" is that you expect is to see all the count values, but only see the last. – outis Sep 16 '11 at 15:04

5 Answers5

3

How about something like this:

var out = document.getElementsByTagName("span")[3];
var speed = 1;
var i = 0;
function loop() {
    out.innerHTML = "Cycles " + i;
    // do something
    if (++i < 10) {
        setTimeout(loop, speed);
    }
}
loop();

If it's happening too fast to watch the time, just increase speed. If you set speed to 100, you'll see the counter increment about 10 times per second, depending on how long it takes for your code to execute.

gilly3
  • 87,962
  • 25
  • 144
  • 176
2

This will update your display once per second.

DEMO: http://jsfiddle.net/Lb3Uc/

var span = document.getElementsByTagName("span")[3];
var i = 0;
(function looper() {
    if( i++ < 10 ) {
        span.innerHTML = "Cycles: " + i;
        setTimeout( looper, 1000);
    }
})();

Every time the looper function runs, as long as i < 10 it recursively invokes itself after a 1000ms delay.

This sort of asynchronous code is required in order to allow the page to redraw.

user113716
  • 318,772
  • 63
  • 451
  • 440
1

In your function you are not adding but replacing the content of your span. Use the += operator instead

http://jsfiddle.net/9wKQw/

for (var i = 0; i < 10; i ++) {
    document.getElementById("oput").innerHTML += "Cycles: " + i + "<br>";
}
Joseph Marikle
  • 76,418
  • 17
  • 112
  • 129
  • I'd like it to be replaced, not added, so you can see the numbers changing (like a percentage for a loading screen) instead of being constantly output. – Aaron Sep 15 '11 at 22:15
1

Your for loop is actually doing exactly what you'd like it to do, but the javascript is executing so quickly you're getting straight to the final cycle faster than you can notice it changing. Try writing your var i to the console and you'll see what I mean. It's printing on every cycle, but it seems almost instant because the script isn't taking any time to execute.

EDIT:

Per your request, here's how you would slow your application down so you could implement your timer...

var i = 0;
var interval = setInterval(
    function() { 
        /* add the rest of your method here */
        document.getElementsByTagName("span")[3].innerHTML = "Cycles: " + i;
        i++; 
        if(i > 10) { /* number of repetitions */
            clearInterval(interval);
        }
    },
1000); /* seconds delayed */
65Fbef05
  • 4,492
  • 1
  • 22
  • 24
  • So how can I use setInterval or something similar to showcase a delay? – Aaron Sep 15 '11 at 22:24
  • 1
    Are you actually saying you want to make your app SLOWER so that the user can see it hit each individual step? – JohnFx Sep 15 '11 at 22:35
  • @Aaron - If you'd like to slow your script down using `setInterval`, my revision above should drive you in the right direction. I'm with @JohnFx on this though; why would you want to slow it down for just a timer? – 65Fbef05 Sep 15 '11 at 22:48
  • The actual function takes about 1 second to process, it's an AJAX function that hasn't been optimized. – Aaron Sep 15 '11 at 22:56
0

To coordinate the AJAX function and the progress update view, don't artificially slow down the function calls. For one thing, it will reduce response time, which the user won't like. For another, the progess will be off by one.

Instead, have the AJAX function call a function that updates the progress when the AJAX call completes either successfully or conditionally, depending on what's appropriate.

Lastly, you may need to change the document structure, which will necessitate changing how you get the progress element. Instead, give the progress element an ID and use getElementById.

var async_done = (function() {
    var doneCount = 0;
    return function () {
        ++doneCount;
        document.getElementById("Progress").innerHTML = "Cycles: " + doneCount;
    };
})();

for (var i = 0; i < 10; i ++) {
    async_function(async_done);
}
outis
  • 75,655
  • 22
  • 151
  • 221