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:
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:
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 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 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:
{
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:
{
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:
{
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 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:
{
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.
09/06/2007 - 12:41
Very nice tutorial. Especially the scope explanation.
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.
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.
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
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.
03/28/2011 - 01:47
I think you probably mean JavaScript, and not Java.
01/29/2008 - 14:48
very helpful indeed, both setTimeout and setInterval are useless in an oop context without your helpful workarounds. thanks again!
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.
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.setVal(9);
obj.causeTimeout();
obj.setVal(10);
A fix is to use an anonymous function in setTimeout. I've dropped the internal value:
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":
timoutFunc = function(x) { alert(x); }
return {
causeTimeout: function(id){
setTimeout(function(){ timoutFunc(id)},2000);
}
}
}
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!
04/11/2008 - 01:39
You saved me :)
04/17/2008 - 08:03
Hi, the following code is not working for me, help me to see why.
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)
}
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
06/12/2008 - 09:15
here's a little trick to get around the window scope problems when working inside an object:
var thisClass = this;
this.myMethod = function(){
alert("made it");
window.clearTimeout(this.intTimer);
}
this.intTimer = window.setTimeout(function(e) {
thisClass.myMethod()},5000)
}
}
MyClass();
06/29/2010 - 04:07
This...is BRILLIANT!!!
Wow, I cannot put into words how much this helps!!! Thank you!!!
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 :)
07/06/2008 - 22:31
Thanks so much! This completely clarified a muddled mess for me.
08/07/2008 - 21:55
Brilliant, a clear and straight forward explanation.
(finally understand the global bit)
Thank You!
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!
11/06/2008 - 23:08
Its great and brilliant tutorial, a clear and straight forward explanation of variable scope, setTimeout and setInterval.
Regards.
Angelina
12/04/2008 - 19:34
Fantastic! Thank you so much!
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.
07/20/2009 - 16:24
yeay! this article solved a problem i've been trying to get around all day. thanks, really!
02/25/2010 - 09:32
Thanks, the scope part was very helpful.
04/12/2010 - 11:28
Thanks for the scoping info! I've spent hours trying to make my code work, never guessing the reason.
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
03/24/2011 - 05:11
Thanks so much - I finally understood, this was extremely helpful.
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
06/28/2011 - 21:43
you should be able to put the setInterval function into window.onload = function(){ intervalID = setInterval();}.
07/26/2011 - 00:00
Thanks,
this helped me understand and solve my scopeing issue.
Mattijs
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();
11/30/2011 - 03:34
{
function bar()
{
alert(i);
}
setTimeout(bar, 500);
}
foo(5);
So is the function 'bar' available in the global scope? And why?
12/13/2011 - 10:59
Is there any way to detect if a variable is running setTimeout or setInterval?
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.
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:
{
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!
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.elapseIntervalyou can declare in beginnig of the "class" or change to a fixed value!Add Comment
[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.