Search code examples
javascripthtmlsettimeoutsetintervalthread-sleep

How do you time consecutive events in the browser, using Javascript in an HTML script tag?


I have just started learning JavaScript, coming from a Java/Clojure background and I am trying to do a simple thread-sleep command that will allow me to have lines of text appear on the screen, at one second intervals. I thought about using the setInterval function instead, but because I am dealing with multiple functions, I thought setTimeout would be better. The problem I am encountering is that all of the text is printing in the browser instantaneously, as though the setTimeout functions weren't even there. Below is an example using the "Happy Birthday" song, which I think succinctly illustrates the problem. How can I make the program below run, line by line, at one second intervals?

<!doctype html>
    <html lang="en">
        <head>
            <meta charset="utf-8">
            <title>Happy Birthday</title>
        </head>
        <body>
            <script>
                var name = "Joe",
                    i = 0;

                while (i < 2) {
                    setTimeout(document.write("Happy Birthday to you!<br>"), 1000);
                    i ++;
                }
                setTimeout(document.write("Happy Birthday dear " + name + ",<br>"), 1000);
                setTimeout(document.write("Happy Birthday to you!<br>"), 1000);
            </script>
        </body>
    </html>

Solution

  • To delay evaluation of some code, this code should be put into a function; that function reference should be passed into setTimeout. For example:

    setTimeout(function() {
        document.write('Hello world!');
    }, 1000);
    

    As it stands, you evaluate document.write expression instead immediately - that's why you see all the writings occurring simultaneously.

    As a sidenote, please please please don't use document.write unless you're really know what're you're doing. It's quite easy to 'log' something just by adjusting innerHTML of log element. For example:

    <div id="log"></div>
    <script>
      var log = document.getElementById('log');
      setTimeout(function() {
        log.innerHTML += 'Hello world!<br />';
      }, 1000);
    </script>
    

    Also, don't forget that each timeout is processed independently. To set up a chain of events, you'd manually increase the delay - otherwise all the functions will be called almost immediately after each other.

    Overall, here's how it can be done:

    <div id="log"></div>
    <script>
    var name = "Joe",
        i = 0,
        delayedMessage = function(msg) {
          setTimeout(function() {
            document.getElementById('log').innerHTML += msg;
          }, ++i * 1000);
        };
    
        delayedMessage("Happy Birthday to you!<br>");
        delayedMessage("Happy Birthday to you!<br>");
        delayedMessage("Happy Birthday dear " + name + ",<br>");
        delayedMessage("Happy Birthday to you!<br>");
    </script>
    

    Demo.