arguments.callee web design & development blog  


Passing Arguments to setTimeout and setInterval

(skip intermediate solutions)

Often, we need to use setTimeout and setInterval but also need to pass arguments to the function being called. There are a handful of ways to do this.

    // Example 1, BAD! :(
    var hello = 'Hello World!';
    setTimeout("alert('" + hello + "')", 1000);

Example 1 works, but it is not the generally accepted syntax for setTimeout. Passing code as a string relies on the same behavior as eval, and eval is usually evil for reasons that are beyond the scope of this post... No pun intended. As an aside, this method is often restricted by Adobe AIR, because of the implied eval. Here's the common workaround:

    // Example 2, better :)
    var hello = 'Hello World!';
    setTimeout(function() {
        alert(hello);
    }, 1000);

Using a closure is a much better solution than supplying a string as in the first example, but it can seem bulky. Turning our little alert into a closure has basically doubled the amount of code required! Okay, it's still short, but it's not quite as clear as what we would like to do: 

    // Example 3, best! :D
    var hello = "Hello World";
    setTimeout(alert, 1000, hello);

The call to setTimeout in Example 3 is clear about what arguments are being passed, rather than having to read through the closure to see what variables it might refer to. The good news is that Example 3 already works on modern browsers (including Adobe AIR). The common implementation for both setTimeout and setInterval allows you to pass additional arguments by simply... passing additional arguments. Awesome.

The exception to this rule is, of course, IE. At least up through version 7, but probably including version 8, IE will simply ignore extra arguments supplied to setTimeout and setInterval. It won't even throw an error, which can make this situation hard to debug (and is probably why this method is not as widely seen as using a closure). However, here's a bit of code I originally ran across on Web Reflection that extends this behavior to IE. 

    // Example 4, keep reading if this is confusing, don't worry...
     /*@cc_on
    (function(f) {
        window.setTimeout = f(window.setTimeout);   // overwrites the global function!
        window.setInterval = f(window.setInterval); // overwrites the global function!
    })(function(f) {
        return function(c, t) {
            var a = [].slice.call(arguments, 2);    // gathers the extra args
            return f(function() {
                c.apply(this, a);                   // passes them to your function
            }, t);
        };
    });
    @*/

First things first, NO you do not have to retype the above code every time you want to use setTimeout. Example 4 actually changes the way setTimeout and setInterval behave. You would include Example 4 at the top of your script, first (or early) in the code. Then you can call setTimeout and setInterval with additional arguments the same way across all browsers. This code makes Example 3 work everywhere.

Of special note is the conditional comment, /*@cc_on ... @*/. If you use a JavaScript minifier, it may consider that whole block of code a comment and delete it... Not good. A less semantic but more reliable alternative is to use object detection to identify IE, typically something like if (("ActiveXObject" in window) && !("opera" in window)) { ... }

Tags




blog comments powered by Disqus
search blog
  • Pro-HTML5-Programming-Application-Development
  • Learn-iPhone-iPad-Web-Development
categories & tags
random posts
about hb stone

I'm a Front-End Engineer at Yahoo! working on the Mail and Messenger teams. I blog about web design and development topics including accessibility, usability, performance, and developing HTML / CSS / JavaScript applications on Appcelerator Titanium and Adobe AIR.

If you're a web developer, you might enjoy Jelo, my JavaScript library.

  • Learning-JQuery-1-Jonathan-Chaffer
  • Deploying-HTML5-Aditya-Yadav
copyright

All original work on this site is covered by a Creative Commons Attribution 3.0 license unless otherwise specified.

You may share or use any code or images from this site in any manner, for free, so long as reasonable effort has been made to give credit where due.

The views expressed in the posts and comments on this blog do not necessarily reflect the views of Yahoo!