JavaScript’s setTimeout and how to use it with your methods

Update: My solution does not work in IE. Look at this article for comprehensive info.

While working on Chatcreator’s Chatbox I run into problems with JavaScript’s setTimeout function. I would like to write down what I learned. It may save you some time, next time you’ll need to use this function.

Shortly about setTimeout

setTimeout is a simple JavaScript function used to repeatedly call some function after a specified amount of time. It takes two required parameters and an unspecified number of optional ones. Like this:

setTimeout(functionToCall, time, param1, param2, ....);functionToCall is the name of the function which will be called after time millisecond. You either use reference like in the example above or a string representing a call to the function:

setTimeout('functionToCall()', time, ...)The optional parameters can be used to pass any number of parameters to our functionToCall.

Where’s the catch?

Everything works as expected until you try to call a method inside your ‘class’ (there are no real classes in JavaScript). Something like this won’t work:

setTimeout(this.methodToCall, time);Passing a string representation instead of reference doesn’t work either.

The solution

I found the solution after a while searching in Google Code Search. The above example needs to be rewritten like this:

setTimeout(function(thisObj) { thisObj.methodToCall(); }, time, this);Here we are passing reference to our class as an optional parameter of the setTimeout function. In the called function we catch it and suddenly we can use it to call our method. I have no idea why such a simple thing needs to be so complicated but it only demonstrates that you need to learn a few tricks when you want to do real OOP in JavaScript.

27 Responses to “JavaScript’s setTimeout and how to use it with your methods”

  1. Alex Le Says:

    Oh btw,

    your above setTimeout() solution only works for Firefox. For IE, it fails since IE’s version of setTimeout doesn’t allow you to pass in extra argument.

    I’ve found the solution for IE and the link is http://alexle.net/archives/169

    Cheers!

    Alex

  2. klevo Says:

    Thank you very much for that link Alex. That article is great.

    You’re right that this solution does not work in IE, I’ll rewrite the article a bit. Now that I am on Ubuntu I sometimes forget THE browser :)

  3. Pat Says:

    You can get around all this by using the fact that Javascript variables are global unless defined inside a function. Simply define the variables you want to manipulate and pass around before any function definitions, then change them inside your function(s).

    E.G.

    // REQUIRED GLOBAL VARS
    var timer = 2000;

    var counter1 = 0;
    var images1 = new Array();
    images1[0] = ‘icons/andy.jpg’;
    images1[1] = ‘icons/condi.jpg’;
    images1[2] = ‘icons/hotzone.jpg’;
    var numImages1 = images1.length;

    var counter2 = 0;
    var images2 = new Array();
    images2[0] = ‘icons/beeftenderloin.jpg’;
    images2[1] = ‘icons/choosingwine.jpg’;
    images2[2] = ‘icons/datenightsalmon.jpg’;
    var numImages2 = images2.length;

    function switchImages(){
    if (document.getElementById(”img1″)){
    document.getElementById(”img1″).src = images1[counter1];
    counter1++;
    if(counter1 >= numImages1){
    counter1 = 0;
    }
    }
    if (document.getElementById(”img2″)){
    document.getElementById(”img2″).src = images2[counter2];
    counter2++;
    if(counter2 >= numImages2){
    counter2 = 0;
    }
    }
    setTimeout(”switchImages()”, timer);
    }

  4. klevo Says:

    yes, that’s a way to do it. thanks Pat.

  5. David Says:

    Scope is crazy in Javascript. See the following. Watch the variable appt_extrainfo_div. This is almost sudo code as I’ve replaces some of my own functions with their basic function. Specifically somediv.onclick = function(){} is something I have a function for that handles various browser differences. Just don’t copy/paste and expect to work.

    Being a C programmer, I can’t say this jives with “my” way of doing things, but it is how JS does it.

    Tested in IE7

    function PopupBoxShow(div,x,y)
    {
    // set div’s style to show up and position somewhere
    }

    function MyFunc()
    {
    var appt_extrainfo_div=document.createElement(’div’);
    // do some stuff in the div. make it hidden for now.

    // Clicking another div makes this extrainfo div appear after 2 seconds.
    someotherdiv.onclick = function () {
    var x=window.event.clientX; // for non-IE, you should do something better here.
    var y=window.event.clientY;
    global_popup_timer = setTimeout( function () {
    //
    // YES! I have access to appt_extrainfo_div because
    // my function was declared in the function it exists in.
    // Even though the function returns before the “click”
    // happens, the reference to this variable is allowed
    //
    PopupBoxShow(appt_extrainfo_div, x, y);
    }, 2000);
    }
    }

  6. chuck Says:

    This will also work (the solution by Alex Le is a bit long-winded and uses ‘eval()’):

    thisObj = this;
    setTimeout(function() { thisObj.methodToCall(); }, time);

  7. Ryan Schutt Says:

    If you are using the prototype javascript, you can take advantage of its general purpose early-binding function, bind (see http://alternateidea.com/blog/articles/2007/7/18/javascript-scope-and-binding).
    The solution using prototype’s bind function is:

    setTimeout(this.methodToCall.bind(this), time);

  8. Sumanth Says:

    your above setTimeout() solution only works for Firefox. For IE, it fails since IE’s version of setTimeout doesn’t allow you to pass in extra argume.

    http://www.sumanth.in

  9. Piyush Says:

    No solution is working for me in IE:(. I want to close the window after submitting the form. But before closing the window i want to wait for few seconds. this is how i am doing it…
    …………..
    formId.submit();
    thisObj = this;
    setTimeout(function() { hisObj.closeWindow();},3000);
    ….
    function closeWindow(){
    window.opener.focus();
    window.close();
    }

    Please help me out….

  10. piotr Says:

    chuck’s approach is almost perfect. I rather use:

    thisObj = this;
    setTimeout(function() { thisObj.methodToCall.call(thisObj); }, time);

    which enusure you that scope is correctly passed.

  11. Thank you for your post!
    Even David Flanagan’s book example code fails in Firefox. I used Firebug to set breakpoints, but the function was never called.

    example 14.6

    var WastedTime = {
    start: new Date(), // Remember the time we started
    displayElapsedTime: function() {
    var now = new Date(); // What time is it now
    // compute elapsed minutes
    var elapsed = Math.round((now - WastedTime.start)/60000);
    // And try to display this in the status bar
    window.defaultStatus = “You have wasted ” + elapsed + ” minutes.”;
    setTimeout(WastedTime.displayElapsedTime, 1000);
    }
    }
    // Update the status line every minute
    setTimeout(WastedTime.displayElapsedTime, 1000);

  12. Elizebeth Says:

    How about setting more than 1 timeout (for different function)?

    Let say I have function A that give warning about session ending soon ask if user wants to refresh the session, and function B that stop a session. I’ll need to set timeout for function A 30 seconds before function B.

    I’ve tried
    timer1 = window.setTimeout(’A()’, 30000);
    timer2 = window.setTimeout(’B()’, 60000);

    This works well in FireFox, but in IE, it don’t get to execute function B if i didn’t click ok on alert() or reply the confirm() in function A.

    Do you have any idea?

  13. Douglas Says:

    The following works in IE 7, but not in Firefox 3.0.1. Please assist:

    var c=0;
    function DisableClick()
    {
    var objName = ‘btnPost’;
    document.getElementById(objName).disabled=true;
    c=c+1;
    msg = ‘Please Wait…(’+ c +’)!’;
    document.getElementById(objName).value= msg;
    var t=setTimeout(’DisableClick()’,5000);
    }

  14. Douglas Says:

    I think I figured the above problem out. FireFox does not like the recursive call to setTimeout. The below javascript disable button code works in both IE and FF, but use an HTML input control to runat server, like this:

    var objName = ‘btnPost’;
    function DisableClick()
    {
    document.getElementById(objName).disabled = true;
    setTimeout(’EnableClick()’, 5000);
    }
    function EnableClick()
    {
    document.getElementById(objName).disabled = false;
    }

  15. Douglas Says:

    I have to add one more comment. To make the code above work in Firefox I needed to remove several Microsoft .Net 2.0 regular expression controls. They seem to intefere with Firefox postback javascript. I’m guessing this is the case with all Microsoft client side validation controls.

  16. bhaiyalal Says:

    i have the problem of time dealay in mozila 2.0 of 25 to 75 ms per seconds so in 10 minute i got the 30 to 40 seconds difference how can i solve it

  17. Junix Says:

    Thanks! I really helps.

  18. Antibland Says:

    It’s articles like this that make me help someone else. From author to commenter: excellent job.

  19. Bacter Says:

    Try this solution:

    var toDelay = function() { animate( type, numb, _this ); };
    setTimeout( toDelay, flakes[numb].timeout );

  20. Bacter Says:

    Try this solution:
    function animate( type, numb, _this ){
    var toDelay = function() { animate( type, numb, _this ); };
    setTimeout( toDelay, flakes[numb].timeout );
    }

    link: http://lejnieks.com/2008/08/passing-arguments-to-javascripts-settimeout-method-using-closures/

    works in IE and FF

  21. jeroen Says:

    Thanks!!
    Very helpful!!

  22. Zeder Says:

    What Chuck said. I was even able to omit the first line/step from his solution, leaving simply:

    setTimeout(function() { this.MethodToCall(); }, time);

    which worked for me in IE 8 but, alas, not in FF 3.0.10 (for which I had to revert to his original solution).

  23. Eero Anttila Says:

    Here’s a full solution:

    function thisReferencingCallback(instance, method) {
    return function() {
    return method.apply(instance, arguments);
    }
    }

    setTimeout(thisReferencingCallback(this, someMethod), 50);

  24. eleman Says:

    hello,
    i use;

    function method(){
    if(document.getelementbyid(id)<200){
    document.getelementbyid(id).style.left=document.getelementbyid(id).offsetLeft+10;//that line
    setTimeout(method(),1000);
    }
    }

    to see a slow slide effect.
    but i just see my div on 200px right of the left edge of browser :S
    where am i wrong?
    should not it shows the effect of single “that line”?
    thanks in advance

  25. eleman Says:

    ok, it is solved thanks

  26. Иван Says:

    Thank you very much about that solution!

  27. Eyedia Says:

    Thanks! It really great and helpful.

Leave a Reply