1

In my javascript code i have the following:

function foo(param1) {
    setInterval( bar(param1), 3000 );
}

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

function set() {
    foo('hello');
}

And on page load i call set(), it gives the alert message only once. Why it does not work as i would expect.? I think the problem is with the parameter that i am passing the foo() function, but what it is exactly, i am not able to figure out.

If the problem is with the parameter, what can be an alternate way to achieve the desired result.?

Thanks.

pratik
  • 119
  • 10

3 Answers3

2

The best way is to use a closure to access the parameter from a function that you pass to setInterval:

function foo(param1) {
    setInterval(function () {
        bar(param1);
    }, 3000);
}

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

function set() {
    foo('hello');
}
Community
  • 1
  • 1
Phil Booth
  • 4,853
  • 1
  • 33
  • 35
  • 3
    For my daily dose of pedantry, there are no closures in this code. From the question you linked to: "That is not a closure. A closure is when you return the inner function. The inner function will close-over the variables of foo before leaving." – jbabey Jan 16 '13 at 16:59
  • @jbabey Fair enough, I stand corrected. :) So I can correct the answer, what's the proper term for a function accessing variables from its parent context? – Phil Booth Jan 16 '13 at 17:03
  • @PhilBooth it's just an anonymous function declaration declared inside a named (`foo`) function declaration. – jbabey Jan 16 '13 at 17:04
  • @jbabey Actually, having read the comments to that answer, the other answers to that question and the article about closures on wikipedia, I disagree. :) It's not necessary to *return* the function for it to be a closure, only that the function runs and has access to the enclosing context after the parent function has already returned. Which it does, in this case. – Phil Booth Jan 16 '13 at 17:49
  • I have a doubt regarding this. For the function `bar(param1)` that will be called at an interval of 3 secs; in which context/scope will it be called.? Will `setInterval(function() { bar(param1); }, 3000 );` translate to `setInterval(function() { bar('hello'); }, 3000 );` when the function `foo(param1)` is called as `foo('hello');` .? I am asking this because at the next interval when `bar(param1)` gets called, it will not be inside `foo(param1)`, so at this time, what will be the value of `param1` that will be passed as `msg`to `bar(msg)` .? Its confusing. – pratik Jan 17 '13 at 08:23
  • 1
    @pratik That scenario is fine. The way to think about it is that you are defining a brand new function every time you invoke `foo` and those functions all have perpetual, dynamic access to their context. A second invocation of `foo` in your case will create a second closure, which accesses a second context. The scenario to be careful of is when you want to define a closure inside the body of a loop. In that case you must call a function outside the body of the loop, fixing the context of each loop iteration, otherwise every closure will refer to a single context (the terminal loop iteration). – Phil Booth Jan 17 '13 at 09:51
  • @Phil Ok, I got some some idea about this from your explanation. So the function `bar(msg)` will be called in the `foo(param1)` context at each interval because the function `bar(msg)` was defined in `foo(param1)`. About the 2nd scenario you mentioned about the terminal loop iteration, its really tricky and i have experienced it personally :D. Learning from mistakes :).. Thanks. :) – pratik Jan 17 '13 at 11:44
1

setInterval expects a function while you're giving the return value of calling the whole function.

A modified version that should work:

var msg = null;

function foo(param1) {
   // When foo is called, its argument is set to msg variable, so the function called 
   // by setInterval will have access to the message that must show in a window.alert
    msg = param1;
    setInterval(bar, 3000 );
}

function bar() {
    alert(msg);
}

function set() {
    foo('hello');
}
Matías Fidemraizer
  • 63,804
  • 18
  • 124
  • 206
  • While this will work with the global variable, i want `bar(msg)` to alert exactly the parameter `msg`'s value that i have passed to it. – pratik Jan 16 '13 at 17:00
  • @patrik You're not right. This approach does what you want. Other discussion is that the closure approach is better, but I just wanted to show you were your code was wrong and a basic hint on how to get it working. – Matías Fidemraizer Jan 16 '13 at 19:01
  • Yes, your answer is right and it does the job, but what if i do not want to create a global variable.? So in that case i will have to use the anonymous function approach. – pratik Jan 17 '13 at 08:26
  • @pratik In my devs, I would never use global vars. I thought you could – Matías Fidemraizer Jan 17 '13 at 08:42
  • Nope, even i do not want to use global vars. I should have been more specific about that in the question. – pratik Jan 17 '13 at 10:19
  • @pratik The comment was sent in a wrong way. I mean that the problem in your question was your misunderstanding of what `setInterval` expects. Actually I don't like to provide the exact solution, I thought you could go beyond an SO answer ;) – Matías Fidemraizer Jan 17 '13 at 11:21
  • Yes, correct, the problem was i misunderstood the parameter that `setInterval()` expected, and the answers cleared that. Thanks. :) – pratik Jan 17 '13 at 12:08
1

You need to pass a function to setInterval, you are executing a function and passing it's return value (undefined since the function executed does not have a return value).

Try using an anonymous function instead:

function foo(param1) {
    setInterval(function () {
        bar(param1);
    }, 3000);
}

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

param1 never changes here, so there is no need for anything more complicated. Here's a working example.

jbabey
  • 45,965
  • 12
  • 71
  • 94