1

I would like to animate an html page with something like this:

function showElements(a) {   
  for (i=1; i<=a; i++)  {  
    var img = document.getElementById(getImageId(i));  
    img.style.visibility = 'visible';  
    pause(500);  
  }  
}

function pause(ms) {
  ms += new Date().getTime();
  while (new Date() < ms){}
}

Unfortunately, the page only renders once javascript completes.

If I add

 window.location.reload();

after each pause(500); invocation, this seems to force my javascript to exit. (At least, I do not reach the next line of code in my javascript.)

If I insert

 var answer=prompt("hello");

after each pause(500), this does exactly what I want (i.e. update of the page) except for the fact that I don't want an annoying prompt because I don't actually need any user input.

So... is there something I can invoke after my pause that forces a refresh of the page, does not request any input from the user, and allows my script to continue?

1

5 Answers 5

2

While the javascript thread is running, the rendering thread will not update the page. You need to use setTimeout.

Rather than creating a second function, or exposing i to external code, you can implement this using an inner function with a closure on a and i:

function showElements(a) {
    var i = 1;
    function showNext() {
        var img = document.getElementById(getImageId(i));  
        img.style.visibility = 'visible'; 
        i++;
        if(i <= a) setTimeout(showNext, 500);
    }
    showNext();
}

If I add window.location.reload(); after each pause(500) invocation, this seems to force my javascript to exit

window.reload() makes the browser discard the current page and reload it from the server, hence your javascript stopping.


If I insert var answer=prompt("hello"); after each pause(500), this does exactly what I want.

prompt, alert, and confirm are pretty much the only things that can actually pause the javascript thread. In some browsers, even these still block the UI thread.

Sign up to request clarification or add additional context in comments.

Comments

1

Your pause() function sleeps on the UI thread and freezes the browser.
This is your problem.

Instead, you need to call setTimeout to call a function later.

Comments

1

Javascript is inherently event-driven/non-blocking (this is one of the great things about javascript/Node.js). Trying to circumvent a built in feature is never a good idea. In order to do what you want, you need to schedule your events. One way to do this is to use setTimeout and simple recursion.

function showElements(a) {   
  showElement(1,a);
}

function showElement(i, max) {
   var img = document.getElementById(getImageId(i));  
   img.style.visibility = 'visible';
   if (i < max) {
      setTimeout(function() { showElement(i+1, max) }, 500);
   }
}

1 Comment

Thanks for saying something basic that didn't come across clearly when I went through javascript tutorials: "Javascript is inherently event-driven/non-blocking". I only came to realize the implications of this now that I have to use timeout functions.
0
var i = 1;
function showElements(a) {   
    var img = document.getElementById(getImageId(i));  
    img.style.visibility = 'visible';  
    if (i < a) {
      setTimeout(function() { showElements(a) }, 500);  
    }
    i++;
}
showElements(5);

5 Comments

This will fail if you do something like hideAllElements(), then later call showElements(5) again, since i will not be reset.
that condition wasn't asked in the question
Hence there being no downvote. It's just something to be aware of.
Sorry, but in your answer, calling hideAllElements() will hide all elements and then if it was called before i == a condition happens, then the previous showElements will still continue running
Good point. That's unavoidable without cooperating implementations of showElements and hideAllElements though - every answer here has that fault.
0
function showElements(a,t) {   
  for (var i=1; i<=a; i++)  {  
    (function(a,b){setTimeout(function(){
      document.getElementById(getImageId(a)).style.visibility = 'visible'},a*b);}
    )(i,t)  
  }  
}

The t-argument is the delay, e.g. 500

Demo: http://jsfiddle.net/doktormolle/nLrps/

10 Comments

You don't need a closure on a*b here
Also, this just makes the ath element visible a times in a row
Ok, you tricked me on the second point, but my first point stands.
a*b is not a closure, it's the milliseconds for setTimeout
I guess the thing that's odd to me here is that you pass 500 into the anonymous function.
|

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.