Lessons on setTimeout() and clearTimeout()

My world was rocked the other day while looking through some source code for a Javascript widget at work. Normally, I'm the one giving lessons in JS techniques, but I was absolutely floored to see how my coworker had used setTimeout() and clearTimeout() in ways I'd never seen before.

A Simple Example

Ok, so if you've done more than a little bit of JS development, you probably have made use of Javascript's setTimeout() method. You may not have made use of clearTimeout() — I didn't know it existed until I saw it in the code — but its purpose should be clear enough from the name, and I'll use it in an example later. Let's create a simple example of using setTimeout():

<div id="clock"></div>
<InvalidTag type="text/javascript">
    var clockDisplay = document.getElementById('clock');

    function updateClock() {
        var time = new Date();
        clockDisplay.innerHTML = time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds();

        setTimeout('updateClock()', 1000);
    }

    updateClock();
</script>

Ok, so that is a simple little clock that ticks along as you go... not the best constructed Javascript, but it shows what you can do with setTimeout().

It takes a Function

What I'd never realized was that setTimeout() accepted a function name instead of a string for execution, and that if you passed a function name, it respects encapsulation. That means you can get away with some better formatted code like this:

<div id="clock"></div>
<InvalidTag type="text/javascript">
    (function() {
        var clockDisplay = document.getElementById('clock');

        function updateClock() {
            var time = new Date();
            clockDisplay.innerHTML = time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds();

            setTimeout(updateClock, 1000);
        }

        updateClock();
    })();
</script>

This is much nicer! The code has been nicely wrapped up so that it executes on load and keeps things isolated in its own tiny encapsulation.

What Really Blew My Mind

What really blew me away is that setTimeout() returns a value. What?

clock = setTimeout(updateClock, 1000);

Is valid, and not only is it valid, the clock variable is useful! What for? For clearTimeout() of course! By passing the value returned from setTimeout() to clearTimeout() you can stop an existing timeout from executing. Now, let's look at a slightly expanded example that shows this better:

<div id="clock"></div>
<button id="start">Start</button>
<button id="stop">Stop</button>
<InvalidTag type="text/javascript">
    (function() {
        var clockDisplay = document.getElementById('clock');
        var clock;

        function updateClock() {
            var time = new Date();
            clockDisplay.innerHTML = time.getHours() + ':' + time.getMinutes() + ':' + time.getSeconds();

            clock = setTimeout(updateClock, 1000);
        }

        updateClock();

    document.getElementById('stop').onclick = function() {
        clearTimeout(clock);
        return false;
        };

        document.getElementById('start').onclick = function() {
            updateClock();
            return false;
        };
    })();
</script>

Here we can see the clock expanded with a button that stops the clock from executing. Along with it, I added a start button so you can test starting/stopping it easily. Our setTimeout() returns a variable that we then store, and the stop click calls clearTimeout with that value to stop it from executing.

What Does This Mean?

This means you can completely leave string based setTimeout() calls behind, and gain a much finer control on the execution of timeout triggers. This probably isn't news to some people, but given that I'd somehow managed to miss this trick in the last 3 years of JS development, I thought I'd blog about it.

If one where really implementing a "clock" type thing, it would be more proper to use setInterval() and clearInterval(). These function just the same as their timeout counterparts, but setInterval() continues to execute until cleared, rather than just once. For example, while I had to set a new timeout ever execution, you could have just set up the interval once with setInterval(). The only down side to this is that if you clear it you have to call setInterval() again.

 

Comments

Robert Zehnder's Gravatar Naming your timer also comes in very handy when you have JSON calls going in the background that might need to clear the timeOut() and start it over. If you do not, you may end up with multiple timers firing since the previous timers were never cleared.

Good post. :)
Jeremy's Gravatar What? No love for setInterval() and clearInterval()?
Jon Hartmann's Gravatar @Robert: Very good point about handling timers... this technique certainly cuts out any annoying flag flipping other hijinxs.

@Jeremy: They get a small mention. I thought about doing a second article talking about them, but they largely follow the same rules. I know that I've seen setTimeout() used way more than setInterval(), so I figure those that know setInterval() have already got my simple stuff down, heh.
Hanlle's Gravatar Thanks for this post friend, =) Gracias por este Post me sirvio de mucha ayuda.
kevin dixon's Gravatar is there any way of making use of this code to play audio samples bang-on-time?
ive already got a timeout function that needs to execute every 117.1875 milliseconds, but its still not accurate using setTimeout.

Could you give any examples?

thanks! :) kev
Jon Hartmann's Gravatar @Kevin, I'm sorry, but I don't think that you're going to find what you're looking for within JavaScript for several reasons. First, all of the *Timeout and *Interval functions are designed for whole milliseconds, not factions. Second, and most important, is that JS is single threaded: you're simply not going to be able to execute your timeout or interval on time if some other process is using the thread when you want to try to use it. Basically, you should read these functions as just saying "wait the given number of milliseconds, and then execute once you can": you can't get an accurate timing, particular on the sub-millisecond level.
azar's Gravatar I have several number of setTimeout, I am populating a table by each call of the setTimeout, so I have different function for each cell. the problem that I have is that, it will never stop, even though I have a command for clearing out the table, and removing setTimeout, they keep repeating. Do you know how I can fix it?
Comments are not allowed for this entry.
Jon Hartmann, July 2011

I'm Jon Hartmann and I'm a Javascript fanatic, UX/UI evangelist and former ColdFusion master. I blog about mysterious error messages, user interface design questions, and all things baffling and irksome about programming for the web.

Learn more about me on LinkedIn.