[ Team LiB ] Previous Section Next Section

4.5 Delaying a Function Call

NN 2, IE 3

4.5.1 Problem

You want a function to run at a specified time in the near future.

4.5.2 Solution

Use the window.setTimeout( ) method to invoke a function once after a delay of a number of milliseconds. You essentially set a timer to trigger a function of your choice. The function is referenced as a string, complete with parentheses, as in the following example:

var timeoutID = setTimeout("myFunc( )", 5000);

The method returns an ID for the time-out operation and should be preserved in a global variable. If, at any time before the delayed function fires, you wish to abort the timer, invoke the clearTimeout( ) method with the time-out ID as the parameter:

clearTimeout(timeoutID);

Once the timer is set, other script processing may proceed as usual, so it is often a good idea to place the setTimeout( ) call as the final statement of a function.

4.5.3 Discussion

It's important to understand what the setTimeout( ) method doesn't do: it does not halt all processing in the manner of a delay that suspends activity until a certain time. Instead, it simply sets an internal countdown timer that executes the named function when the timer reaches zero. For example, if you are creating a slide show that should advance to another page after 15 seconds of inactivity from the user, you would initially set the timer via the onload event handler for the page and the resetTimer( ) function:

var timeoutID;
function goNextPage( ) {
    location.href="slide3.html";
}
function resetTimer( ) {
    clearTimeout(timeoutID);
    timeoutID = setTimeout("goNextPage( )", 15000);
}

You would also set an event handler for, say, the onmousemove event so that each time the user activates the mouse, the autotimer resets to 15 seconds:

window.onmousemove = resetTimer;

The resetTimer( ) function automatically cancels the previously set time-out before it triggers the goNextPage( ) function, and then it starts a new 15-second timer.

If the function you are invoking via the delay requires parameters, you can assemble a string with the values, even if those values are in the form of variables within the function. But�and this is important�the variable values cannot be object references. Parameters must be in a form that will survive the conversion to the string needed for the first argument of the setTimeout( ) method. Recipe 8.4 demonstrates how you can convey names of DOM form-related objects as ways of passing an object reference. The tricky part is in keeping the quotes in order:

function isEMailAddr(elem) {
    var str = elem.value;
    var re = /^[\w-]+(\.[\w-]+)*@([\w-]+\.)+[a-zA-Z]{2,7}$/;
    if (!str.match(re)) {
        alert("Verify the e-mail address format.");
        setTimeout("focusElement('" + elem.form.name + "', '" + elem.name + "')", 0);
        return false;
    } else {
        return true;
    }
}

In this example, the focusElement( ) function requires two parameters that are used to devise a valid reference to both a form object and a text input object. Both parameters of the focusElement( ) function are strings. Because the first argument of setTimeout( ) is, itself, a string, you have to force the "stringness" of the parameters to focusElement( ) by way of single quotes placed within the extended string concatenation sequence. (The zero milliseconds shown in the example is not a mistake for this application. Learn why in the discussion for Recipe 8.4.)

If you are looking for a true delay between the execution of statements within a function or sections of a function, JavaScript has nothing comparable to commands available in some other programming languages. But you can accomplish the same result by dividing the original function into multiple functions�one function for each section that is to run after a delay. Link the end of one function to the next by ending each function with setTimeout( ), which invokes the next function in sequence after the desired amount of time:

function mainFunc( ) {
    // initial statements here
    setTimeout("funcPart2( )", 10000);
}
function funcPart2( ) {
    // initial statements here
    setTimeout("finishFunc( )", 5000);
}
function finishFunc( ) {
    // final batch of statements here
}

The related functions don't have to be located adjacent to each other in the source code. If all related functions need to operate on the same set of values, you can cascade them as parameters (provided the parameters can be represented as nonobject values), or you can preserve them as global variables. If the values are related, it may be a good reason to define a custom object with values assigned to labeled properties of that object to make it easier to see at a glance what each function segment is doing with or to the values.

Another JavaScript method, setInterval( ), operates much like setTimeout( ), but repeatedly invokes the target function until told to stop (via the clearInterval( ) method). The second parameter (an integer in milliseconds) controls the amount of time between calls to the target function.

4.5.4 See Also

Recipe 8.4 for using setTimeout( ) to keep script execution synchronized; Recipe 10.11 for a sequence of three initialization functions that are linked via calls to setTimeout( ) to keep execution synchronicity in order; Recipe 12.3 for an example of using a self-contained counter variable in a repeatedly invoked function to execute itself a fixed number of times; Recipe 13.9 and Recipe 13.10 for applications of setInterval( ) in animation.

    [ Team LiB ] Previous Section Next Section