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.
Very nice tutorial. Especially the scope explanation.
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.
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.
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
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.
I think you probably mean JavaScript, and not Java.
very helpful indeed, both setTimeout and setInterval are useless in an oop context without your helpful workarounds. thanks again!
Thanks, Specially liked the working example at the end. Helped me make my AJAX site aysnchronous and therefore appear faster.
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
A fix is to use an anonymous function in setTimeout. I've dropped the internal value:
Foo can be rewritten to follow the "module pattern":
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!
You saved me :)
Hi, the following code is not working for me, help me to see why.
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
here's a little trick to get around the window scope problems when working inside an object:
This...is BRILLIANT!!! Wow, I cannot put into words how much this helps!!! Thank you!!!
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 :)
Thanks so much! This completely clarified a muddled mess for me.
Brilliant, a clear and straight forward explanation. (finally understand the global bit) Thank You!
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!
Its great and brilliant tutorial, a clear and straight forward explanation of variable scope, setTimeout and setInterval. Regards. Angelina
Fantastic! Thank you so much!
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.
yeay! this article solved a problem i've been trying to get around all day. thanks, really!
Thanks, the scope part was very helpful.
Thanks for the scoping info! I've spent hours trying to make my code work, never guessing the reason.
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
Thanks so much - I finally understood, this was extremely helpful.
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
you should be able to put the setInterval function into window.onload = function(){ intervalID = setInterval();}.
Thanks,
this helped me understand and solve my scopeing issue.
Mattijs
Nice examples,
but what about this:
function foo() {
function bar(i) { alert(i); }
setTimeout("bar('MSG');", 2000); // Wait for 2 seconds! }
foo();
So is the function 'bar' available in the global scope? And why?
Is there any way to detect if a variable is running setTimeout or setInterval?
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.
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:
Sorry for the bad writting english or any code mistake!
hope you enjoy!
Forgot to write a usage example: simple as shoud be...
And the property
you can declare in beginnig of the "class" or change to a fixed value!
Thanks for explanation. This is very helpful.