Javascript Tutorial - Using setInterval and setTimeout

Skill

Javascript Tutorial - Using setInterval and setTimeout

Posted in:

In javascript, the two functions setInterval and setTimeout can be extremely useful and important, but using either of them in complex ways can be a confusing ordeal. In this tutorial, I'm going to try and show the range of possibilities, from the very simple, to the complex, to the 'why oh why is it working like this!?'.

So lets start out with the extremely simple - what do the setInterval and setTimeout functions do? They are both functions attached to the window object of a web page, and they allow, in a very crude manner, a sort of 'thread-like' control.

The setTimeout call lets you tell the browser to execute a javascript call after a certain time has passed. It takes two arguments - what to execute, and how long to wait (in milliseconds). Here is an example of a very simple setTimeout call:

setTimeout("alert('hi!');", 500);

This call will execute the code alert('hi!'); after 500 milliseconds has passed.

The setInterval call has similar arguments, but instead of just executing the given code once, it executes it over and over again, using the second argument as the amount of time to wait between executions. Here is a simple example of a setInterval call:

setInterval("alert('hi!');", 500);

This call will execute the code alert('hi'); every 500 milliseconds from now until the the page it is loaded on is closed.

But if that was all you could do with these two functions, it wouldn't be very interesting, now, would it? Fortunately, that is only the tip of the iceberg.

Both of these functions return an integer id when they are called - which in and of itself is not very useful. But what these ids allow you to do is clear an interval/timeout call if you don't want it anymore. There are two companion funtions called clearTimeout and clearInterval which you can pass these ids to - and they will clear the timeout/interval associated with the id. This especially useful for setInterval, because it is probably rare that you want something on your page executing every X milliseconds for the entire time the user has the page open.

Using the functions is very simple, you can just call them like the following:

var timeoutID = setTimeout("alert('hi!');", 500);
var intervalID = setInterval("alert('hi!');", 500);
clearTimeout(timeoutID);
clearInterval(intervalID);

Granted, that code is kind of silly, because the end result is that nothing will happen (neither the timout or the interval will ever get called). But it shows exactly how to use the clear functions.

An important thing to note about the first argument to both these functions is that they can either take a string or a function reference. A string is what we have been using so far, so lets continue to push on that technique, and I will talk about passing a function reference later.

When a string is passed to these functions, it is evaluated at the time of execution. What this means is that you can pack any kind of valid javascript in the string and it will "get run". For example:

setTimeout("var foo = 2 + 2; alert(foo);", 500);

setTimeout("var abc = 2 + bar; alert(abc);", 500);
var bar = 7;

The first call will cause a pop up with the value 4 to appear after 500 milliseconds. The second call will cause a pop up with the value 9 to appear, also after 500 milliseconds. The first example should make sense, but the second one can be a bit confusing. The reason it works, even though the variable bar was undefined when the setTimeout call was made, is that the contents of that string are not evaluated until after the 500 milliseconds are up. Since at that point, bar does exist, it can evaluate 2 + bar, and come up with 9.

An important thing to note is in what scope these strings are evaluated. They are evaluated in the global scope, so any variables or functions not accessible from the global scope will be undefined when the time comes for the string to be executed. For example:

function foo()
{
  var i = "hello";
  setTimeout("alert(i);", 500);
}

foo();

Instead of popping up the string "hello" after 500 milliseconds, there will be a javascript error saying that i is undefined. This is because i only existed inside the scope of the function foo - and the alert call is executed in the global scope. A place where this often catches people by surprise is inside objects - because the scope changes, the this reference is not maintained:

function foo()
{
  this.val = "hi";

  this.bar = function()
  {
    alert(this.val);
  }

  this.abc = function()
  {
    setTimeout("this.bar();", 500);
  }
}

var obj = new foo();
obj.abc();

When the string here is evaluated in the context of the global scope, the this reference resolves to the window object - which means that this.bar will be undefined, and throw a javascript error. So whenever passing a string to setInterval/setTimeout, you need to be careful that any variables you are referencing will actually exist when the string gets evaluated and executed.

Ok, so thats about it for handing either of these functions a string to evaluate - lets move on to function references. First, a simple example:

function foo()
{
  alert("hi!");
}

setTimeout(foo, 500);

It should be pretty easy to see what this code would result in - the function foo will be called after 500 milliseconds.

In general, it is much easier to think about this method of using setInterval and setTimeout, because you don't have to worry quite as much about who will evaluate to what at execution time. But it does have a significant drawback - there is no way to pass any arguments to the function you want called. Actually, that is not quite true - for Firefox, you actually can, but since you can't do it in both major browsers, I'm not going to go into detail on it here (see the setTimeout and setInterval documentation if you want details on how to do it). But, guess what? There is a way to get around this drawback (most of the time):

function foo(i)
{

  function bar()
  {
    alert(i);
  }

  setTimeout(bar, 500);
}

foo(5);

This code will cause a pop up to show the value 5 - and it is all because of the concept of function references and scope. Since we are now passing an actual function reference instead of a string, we get the added benefit of maintaining the scope of the function (instead of the assumption of global scope). The variable i here existed in the scope of the function bar - so when bar was finally evaluated, the variable i still existed.

This is actually a way to get around the fact that the this reference is never maintained with setInterval and setTimeout. Since the functions maintain their proper scope, we now have the ability to do things like:

function foo()
{
  var internalVal = 5;

  function timoutFunc()
  {
    alert(internalVal);
  }

  this.setVal = function(val)
  {
    internalVal = val;
  }

  this.causeTimeout = function()
  {
    setTimeout(timoutFunc, 500);
  }
}

var obj  = new foo();
obj.causeTimeout();
obj.setVal(9);

This code will alert the value 9 - because while the this reference might not be maintained, the scope of the function timeoutFunc is, and so it knows where the get the variable internalVal.

I hope you found this tutorial helpful, and that you now have a better understanding of how and when to use the setTimeout and setInterval functions. If you have any questions, comments, or crazy ideas about these functions, please leave a comment.

Aleksandr
09/06/2007 - 12:41

Very nice tutorial. Especially the scope explanation.

reply

RobG
09/06/2007 - 22:11

The statement:

"the variable bar did not exist when the setTimeout call was made"

is incorrect. It does exist, since variable declarations are processed before any code is executed. Therefore, when setTimeout is called, bar does exist with a value of "undefined". Just after the call to setTimeout runs, bar is given a value of 7.

reply

The Tallest
09/06/2007 - 22:31

Thanks for pointing that out - I did not actually know that. I've updated the text of the article to say that it is undefined instead of that it doesn't exist.

reply

Boris
09/17/2007 - 09:50

I've stumbled over your tutorial, very nice and clean explanation of the scope problem.
Some time ago I've also written a short tutorial where I've used a different approach to solve the problem, if someone is interested:
SetInterval and objects

reply

Jalil
12/18/2007 - 19:05

I was writing some ajax to beef up some web applications and got stuck with 'not defined' errors and took in three mugs of coffee to mull over it and still could not find out why. and my search on all major java sites turned up no answers.

If it weren't for people like you who make clear of scoping and the problems associated with it, and *plus* a solution or workaroud to it!!!, we developers would be extinct by now.

However, the scoping as done by java is i think real weird and totally unfair as it catches even seasoned programmers, some kind of java games i suppose...heh.

it is obvious, that when a global java function is executed from within a local function scope, the local variable is implied to be global. if not an explixit global command should be made available.

in PHP for example, i can declare a global variable within a function, which is then available globally. there surely must be somethng equivalent in java.

thank you.

reply

hotshot309
03/28/2011 - 01:47

I think you probably mean JavaScript, and not Java.

reply

Chrismarx
01/29/2008 - 14:48

very helpful indeed, both setTimeout and setInterval are useless in an oop context without your helpful workarounds. thanks again!

reply

Jfw
02/07/2008 - 06:03

Thanks,
Specially liked the working example at the end. Helped me make my AJAX site aysnchronous and therefore appear faster.

reply

Jfw
03/07/2008 - 09:16

Good article! This helped me understand scope better.
I ran into an additional wrinkle.. when calling setVal and causeTimeout twice. For example, with this block, you'll get "10" alerted twice

obj.causeTimeout();
obj.setVal(9);
obj.causeTimeout();
obj.setVal(10);

A fix is to use an anonymous function in setTimeout. I've dropped the internal value:

function foo() {

  function timoutFunc(x) {  alert(x); }
 
  this.causeTimeout = function(id){
    setTimeout(function(){ timoutFunc(id)},2000);
  }
}

var obj  = new foo();
obj.causeTimeout(9);
obj.causeTimeout(10);

Foo can be rewritten to follow the "module pattern":

foo = function() {
  timoutFunc = function(x) { alert(x); }
  return {
    causeTimeout: function(id){
      setTimeout(function(){ timoutFunc(id)},2000);
    }
  }
}

reply

Dave
04/03/2008 - 09:51

Do instructions following the setTimeout function call get executed. If it does, it seems as though sometimes more (or less) lines of code may be executed due to how fast system is performing--leading to unpredictable results.

Thanks!

reply

Sandro Filippi
04/11/2008 - 01:39

You saved me :)

reply

Simba
04/17/2008 - 08:03

Hi, the following code is not working for me, help me to see why.

var images=new Array()
images[0]=new Image
images[0].src="Blue hills.jpg"
images[1]=new Image
images[1].src="Sunset.jpg"
images[2]=new Image
images[2].src="winter.jpg"
images[3]=new Image
images[3].src="Water lilies.jpg"
var num
function rotate(index)
{
  books.src =images[index].src
  num=Math.random(Math.floor*images.length)
  setTimeout("rotate("+num+")",500)
}

reply

Andrew
04/17/2008 - 20:56

Many thanks, I was having a real problem passing variables to a function executed by a setTimeout function....You saved my day and thanks to Google where it was ranked No.1 using this search term:
"javascript timeout variable is not defined"

Great Article!

Andrew

reply

Ask
06/12/2008 - 09:15

here's a little trick to get around the window scope problems when working inside an object:

function MyClass(){
  var thisClass = this;

  this.myMethod = function(){
    alert("made it");
    window.clearTimeout(this.intTimer);
  }

  this.intTimer = window.setTimeout(function(e) {  
    thisClass.myMethod()},5000)
  }
}

MyClass();

reply

Mr. Mustachio :{O
06/29/2010 - 04:07

This...is BRILLIANT!!!
Wow, I cannot put into words how much this helps!!! Thank you!!!

reply

SteveWa
07/21/2011 - 12:12

typo: the closing curly brace after the line
thisClass.myMethod()},5000)
} // <= this curly brace

is a type

otherwise it works, thank you!

be aware when you try to run this snippet, it will wait 5 seconds before showing the alert, so don't panic if you don't see anything immediately :)

reply

Kim
07/06/2008 - 22:31

Thanks so much! This completely clarified a muddled mess for me.

reply

Erick
08/07/2008 - 21:55

Brilliant, a clear and straight forward explanation.
(finally understand the global bit)
Thank You!

reply

Robert
10/07/2008 - 11:01

Thanks for a clear explanation of both variable scope, setTimeout and setInterval. I'm sure my AJAX code will improve as a result.

Personally, I much prefer writing PHP. Variable scope is clear, and (almost!) everything seems to work as expected. But, sadly, I can't do everything in PHP!

reply

Angelina
11/06/2008 - 23:08

Its great and brilliant tutorial, a clear and straight forward explanation of variable scope, setTimeout and setInterval.
Regards.
Angelina

reply

Jon Wise
12/04/2008 - 19:34

Fantastic! Thank you so much!

reply

Alex Ndungu
03/16/2009 - 10:12

Your scope rules tutorial is a life saver! I have spent half a day going round in circles and couldn't get to the root of the bug since the code being executed by the setTimeout call isn't accessible to the debugger.

reply

Anonymous
07/20/2009 - 16:24

yeay! this article solved a problem i've been trying to get around all day. thanks, really!

reply

Christophe
02/25/2010 - 09:32

Thanks, the scope part was very helpful.

reply

John Joyner
04/12/2010 - 11:28

Thanks for the scoping info! I've spent hours trying to make my code work, never guessing the reason.

reply

jainprasanna
07/22/2010 - 02:12

Thanks for the tutorial. i have a question related to the second argument passed to the setInterval.
Suppose i have passed setInterval(process(),100). So it should execute process() every 100 milliseconds until i clearInterval.
But what would happen if the previous execution of process() is not complete , i mean suppose the processing of process() was not done in 100 ms, the the setInterval will again call process() at the beginning so will the previous call to process will have some code unexecuted.
Can anyone please explain.

Thanks

reply

Katharine
03/24/2011 - 05:11

Thanks so much - I finally understood, this was extremely helpful.

reply

Flavio
04/09/2011 - 13:04

Hi! First of all, thanks for the tutorial!

I'd like to know if there's a way to set setInterval to call a function immediately at the first load and then starts to count regularly.

Thanks

reply

Anonymous
06/28/2011 - 21:43

you should be able to put the setInterval function into window.onload = function(){ intervalID = setInterval();}.

reply

Mattijs
07/26/2011 - 00:00

Thanks,

this helped me understand and solve my scopeing issue.

Mattijs

reply

Anonymous
10/18/2011 - 08:34

Nice examples,

but what about this:

function foo()
{

function bar(i)
{
alert(i);
}

setTimeout("bar('MSG');", 2000); // Wait for 2 seconds!
}

foo();

reply

m0tv
11/30/2011 - 03:34

function foo(i)
{

  function bar()
  {
    alert(i);
  }

  setTimeout(bar, 500);
}

foo(5);

So is the function 'bar' available in the global scope? And why?

reply

Anonymous
12/13/2011 - 10:59

Is there any way to detect if a variable is running setTimeout or setInterval?

reply

AlexT
01/13/2012 - 20:26

Great tutorial. After reading this I managed to solve a problem in my jquery slider that was driving me crazy. It was scope problem.
Keep up the good work.

reply

Carlos
05/09/2012 - 08:52

I don´t know if it helps, but a strategy to solve the scope problem is use the "call()" method of Object. To ilustrate what i´m trying to say, take a look in this example:

  function Timer()
  {
    this.msg     = 'Hellow World'; //a message
    this.timerID = null; //holds de timer id
   
    //starts
    this.Start = function()
    {
       var obj = this; //reference to the object
       
       // here is the "magic" with obj.Process.call(obj)
       this.timerID = setInterval(function(){ obj.Process.call(obj); }, this.elapseInterval);
    }
   
    //just in case.. if you want to stop the event
    this.Stop = function()
    {
      clearInterval(this.timerID);
    }
   
    //and here where the "action" happens..
    this.Process = function()
    {
      alert(this.msg); //could be a referente to a external method
    }
  }

Sorry for the bad writting english or any code mistake!

hope you enjoy!

reply

Carlos
05/09/2012 - 08:56

Forgot to write a usage example: simple as shoud be...

 
  var t = new Timer();
  t.Start
 

And the property  this.elapseInterval you can declare in beginnig of the "class" or change to a fixed value!

reply

Add Comment

Put code snippets inside language tags:
[language] [/language]

Examples:
[javascript] [/javascript]
[actionscript] [/actionscript]
[csharp] [/csharp]

See here for supported languages.

Javascript must be enabled to submit anonymous comments - or you can login.
CAPTCHA
This question is for testing whether you are a human visitor and to prevent automated spam submissions.