Darknight
Darknight

Reputation: 1152

setTimeout("fn(x)") doesn't work correctly

I have a timer function which alerts a text 'hello, welcome' in a pop up for every 2 seconds. Also I have a function to clear the timer interval so as to stop the pop up at 10th second.

The pop up box showing is stopped when I use the clearInterval function line as

setTimeout(function() {clearInterval(x); },10000);

But the pop up box showing is not stopped when I use the settimeout function as

setTimeout("clearInterval(x);",10000);

However If I use settimeout function to display a pop up by defining the builtin function directly as setTimeout("alert('hello, welcome');",2000); // works properly

Can you please explain why the settimeout function behaves differently for the above two lines. Please find my code below.

<html>
<head>
<script type='text/javascript' >
function testclear()
{
    var x = setInterval("alert('hello, welcome');",2000);
    setTimeout(function() { clearInterval(x); },10000);

   // setTimeout("clearInterval(x);",10000);
}
</script>
</head>
<body>
    <input id='txt' onchange='testclear()' />
</body>
</html>

Upvotes: 1

Views: 301

Answers (4)

ameya rote
ameya rote

Reputation: 1114

Working Example Here I have customised your code and it works fine.

  1. Make x variable global.
  2. var t= setTimeout(' clearInterval(x);' ,1501); set temp variable to catch setTimeout ,it is semantics to follow.

Upvotes: -1

Ian
Ian

Reputation: 50905

I do believe that when you specify a string for the first parameter of setInterval or setTimeout, it will be executed with eval at the specific time/interval. Because of that, it is run in the global scope. In your case, x is not available in the global scope...it's a local variable scoped inside of the testclear function. Passing a function as the first parameter to setInterval or setTimeout secures the scope you were originally working with (inside the testclear function).

Alternatively, yet not preferably, I believe you could do this:

setTimeout("clearInterval(" + x + ");",10000);

But note that this concatenation may be different or not possible in other situations (other method calls)

Upvotes: 1

Shadow Wizard
Shadow Wizard

Reputation: 66388

That's because x is local to the function testclear(). When you pass function to setTimeout, it will get the same scope as the one it was written in, thus x will be recognized.

When you pass string literal, it will be evaluated but the scope is lost.

It will also "work" if x will be global variable, however it's not a good practice.

Upvotes: 0

Thilo
Thilo

Reputation: 262534

But the pop up box showing is not stopped when I use the settimeout function as

setTimeout("clearInterval(x);",10000);

That is because when you eval that string, the variable 'x' has not been properly captured. It will probably point to window.x (and not your local variable that holds the interval timer id).

Whereas the closure in the working example has captured the proper x.

One more reason to avoid eval.

You don't have this problem (yet) with your alert, because it does not reference any variables, but I suggest you also change it to closure ("function") form.

Upvotes: 3

Related Questions