0

I am creating a course for people who have never done programming, and would like to demonstrate basic DOM-manipulation without using async programming or callback functions.

I thought I could do something like this:

function color(element, color) {
    element.style = "background: " + color + ";";
}

function wait(milliseconds)
{
  var e = new Date().getTime() + (milliseconds);
  while (new Date().getTime() <= e) {}
}

function disco() {
    var body = document.getElementById("body")
    color(body, "red")
    wait(500)
    color(body, "darkGreen")
    wait(500)
    color(body, "darkBlue")
}

disco()

This runs fine, but the UI doesn't refresh until the end, so the background never turns red or green - it just ends up blue.

Is there any way to force a repaint during the execution of the function?

I am aware that this not a good idea or even acceptable for an actual implementation, but my aim is to keep things comprihensible to newbies.

severin
  • 5,203
  • 9
  • 35
  • 48
  • 1
    Possible duplicate of [What is the JavaScript version of sleep()?](http://stackoverflow.com/questions/951021/what-is-the-javascript-version-of-sleep) – Andreas Nov 02 '16 at 13:00
  • Is this your exact code? Then you are missing semicolons at the end of the lines inside `disco` function. – elementzero23 Nov 02 '16 at 13:01
  • @elementzero23, semicolons although recommended, are not mandatory. – emerson.marini Nov 02 '16 at 13:07
  • Thanks for your reply Andreas, but the async/promise-version doesn't seem to run without transpilation from ES6 ? – severin Nov 02 '16 at 13:27
  • Read the [highest voted answer](http://stackoverflow.com/a/5992511/402037) for the "why" and [this one](http://stackoverflow.com/a/951111/402037) for a solution without the "fancy new stuff" :) – Andreas Nov 02 '16 at 13:38

2 Answers2

1

While you do your busy waiting, the browser cannot do anything else. This approach is seriously not recommended. Instead, you can set up your disco like this.

var body = document.body;
var colors = [ "red", "darkgreen", "darkblue" ]; 
var nextColor = 0;

function color(element, color) {
    element.style = "background: " + color + ";";
}

function setNextColor() {
  color(document.body, colors[nextColor%color.length];
  nextColor = nextColor + 1;
}

function disco() {
    setInterval(setNextColor, 500);        
}

Please note that this code is only for demonstration of the technique, not tested in any ways.

Zoltán Tamási
  • 12,249
  • 8
  • 65
  • 93
  • Thank you for your reply. While I agree that busy waiting is generally a terrible idea, the purpose of my code is to demonstrate basic programming to complete beginners using the browser, which is why I wanted to avoid using callbacks. Do you have a suggestion how I could use your code to create a concept that is comprehensible to newbies? – severin Nov 02 '16 at 13:26
  • Actually this is **the** concept for such a task in a browser, because of JavaScript being single threaded. I think this concept is understandable for newbies too. It can be a bit simplified by using global variables, I'll edit accordingly. – Zoltán Tamási Nov 02 '16 at 14:01
  • Editied the code. The new version uses `setInterval` to start kind of an async loop, and uses global variables to make the things more straightforward. Also, `getElementById` is not needed to get `body`, simply use `document.body`. – Zoltán Tamási Nov 02 '16 at 14:04
0

You can use setTimeout and style.backgroundColor instead of the functions color() and wait(). I propose this function disco:

function disco(){

    var body = document.getElementById("body");

    time = 0;

    for (var i=0;i<10;i++) // I've put this color to change 10 times, just for test.
    {
        setTimeout(function(){ body.style.backgroundColor = "red"}, time);
        time += 100;
        setTimeout(function(){ body.style.backgroundColor = "darkGreen"}, time);
        time += 100;
        setTimeout(function(){ body.style.backgroundColor = "darkBlue" }, time);
        time += 100;
    }

}
TaoR
  • 51
  • 4