codepuppy
codepuppy

Reputation: 1140

setInterval using a non anonymous function requiring parameters has to be inside an anonymous function. Why?

Ok I have reviewed several postings here and elsewhere regarding setInterval in jquery/javascript the annoying thing about the answers is that I am not learning why the solutions work.

Please consider:

Using an anonymous function we can set an alert to repeatedly output "bunnies":

setInterval(function(){
  alert("bunnies")
},3000);

But if we want to use a non anonymous function we have to code

setInterval(hop,3000);

where funct:

function hop(){
    alert("bunnies");
}

If we attempt to code:

setInterval(hop(),3000);

hop is executed but once only. I do not understand why this is. I have read various SO's on this which imply that we need to be passing a reference to setInterval. Does this imply that the first form setInterval(hop,3000); passes by reference. If so could this be explained?

Therefore we have an issue. In that obviously it would be desireable to be able to pass a parameter to function hop like .....

setInterval(hop("bunnies"),3000);

where funct:

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

This does cause hop to be invoked and "bunnies" to be output but again the function is invoked once only.

So as far as I can work out the only way to pass a parameter to a function being controlled by setInterval is to incorporate it inside an anonymous function:

setInterval(function(){
 hop("bunnies")
},3000);

this passes the parameter and repeats the execution of hop alerting us to bunnies every 3 seconds (very important to be alert to bunnies).

Questions therefore:

  1. Is this the only syntax that will allow you to pass a parameter in.
  2. Why does setInterval(hop("bunnies"),3000); not work.

Upvotes: 10

Views: 7606

Answers (4)

techfoobar
techfoobar

Reputation: 66693

setInterval expects a function as the first parameter. When you attempt:

setInterval(function() {...}, 100);

or

setInterval(funcName, 100);

you are correctly passing a function.

Whereas, when you attempt setInterval(funcName(), 100);, you are actually calling the function and passing its return value to setInterval which is incorrect.

Upvotes: 16

tsterker
tsterker

Reputation: 310

1. Is this the only syntax that will allow you to pass a parameter in?

Yes, this is the only straight forward way I could think of...

setInterval(function(){
    hop("bunnies")
},3000);

... but of course you could write a helper function if you have to handle a lot of intervals, something like:

function Looper() {
    this.loops = {};
    this.start = function(name, fn, interval, params) {
        this.loops[name] = setInterval(function() {
            fn.apply(null, params);  // maybe bind the function?
        }, interval);
    };
    this.stop = function(name) {
        clearInterval(this.loops[name]);
    };
}

(try it: http://jsfiddle.net/ceHMs/)

And you would use it like this:

function say(name, msg){ console.log(name,':',msg) };
function shout(name, msg){ console.log(name,':',msg.toUpperCase()) };

var looper = new Looper();
looper.start('say', say, 1000, ['clock' 'tick']);
looper.start('shout', shout, 2000, ['clock' 'tack']);
// ... later ...
looper.stop('shout');

But you have to evaluate if this really is necessary.


2. Why does setInterval(hop("bunnies"),3000); not work.

This is because setInterval expects a reference to a Function that should be executed every few milliseconds that you specify.

The parenthesis are the key here. A function name followed by parenthesis does execute the given function and returns the result of the function and therefore you would not pass a reference to setInterval but the return value of the function hop('bunnies'). A reference of a function is simply the name of the function. And if you want to call the referenced function, just append parenthesis to the reference. Trivial example:

function executeFunction(fn){
    fn();
};

Knowing this we could actually modify your hop function to make it work with setInterval(hop("bunnies"),3000);:

function hop(msg){
    return function(){ alert(msg) }
}

But this is almost exactly the same as using an anonymous function directly in the setInterval call. Now you just return that anonymous function when calling hop, wich makes you setIntervall call shorter.

In the end it boils down to your personal preferences and the specific use case. Most of the times the approach with an anonymous function directly in your setInterval is the most obvious one and the easiest for others to understand.

Upvotes: 6

Quentin
Quentin

Reputation: 944564

Why does setInterval(hop("bunnies"),3000); not work.

setInterval(hop("bunnies"),3000); will call hop immediately and then pass its return value (undefined) to setInterval (where it will be ignored because it isn't a function or a string).

Is this the only syntax that will allow you to pass a parameter in.

No, but it is the best supported.

The other syntax is

 setInterval(hop, 3000, "bunnies")

Upvotes: 7

Roman
Roman

Reputation: 504

you should pass a function as variable not call it.

setInterval(hop,3000);

Because the first parameter is a function to call by given interval, by putting it like hop() you call the function, not passing it. If you want to pass an arguments use function wrapper

setInterval(function(){hop(arguments)},3000);

Upvotes: 1

Related Questions