5

If I call a named function using setTimeout() and setInterval() without the parentheses it works as expected. When I call the same function with the parentheses it either executes it immediately or gives an error.

I am looking for a deeper understanding in this matter then what I have found on the web. Would you guys please explain to me why this is true?

var func = function(){
    console.log("Bowties are cool.");
}

setTimeout(func(), 1500);
// Prints "Bowties are cool." immediately

setInterval(func(), 1500);
// Throws an error

setInterval(func, 1500);
// Works as expected

setTimeout(console.log("Bowties are cool."),1500);
// This method has the same result as "setTimeout(func(), 1500)".
sufuninja
  • 87
  • 2
  • 8
  • 1
    The `()` operator causes the function to be called, so when you use `func()` in the call to `setTimeout()` the function is called and the *result* (the return value) is passed to `setTimeout()`. – Pointy Aug 21 '15 at 16:32
  • You are supposed to pass a function, not the result of a function (unless it returns a function) - so is it surprising it doesn't work? – Dominic Aug 21 '15 at 16:33
  • Functions are first-class citizens in javascript. You can pass around just like any other variable. When you use the name of a function alone, you are passing a reference to the function. When you use brackets `()` you are calling the function and passing the *result* of that call. – Matt Burland Aug 21 '15 at 16:33

3 Answers3

6

You must pass a function reference to both setTimeout() and setInterval(). That means you pass a function name without the () after it or you pass an anonymous function.

When you include the () after the function name as in func(), you are executing the function immediately and then passing the return result to setInterval() or to setTimeout(). Unless the function itself returns another function reference, this will never do what you want. This is a very common mistake for Javascript programmers (I made the same mistake myself when learning the language).

So, the correct code is:

setTimeout(func, 1500);
setInterval(func, 1500);

If you know other languages that use pointers, you can think of the name of a function with the () after it as like a pointer to the function and that's what a function reference is in Javascript and that's what you pass to a function when you want it to be able to execute some function later, not immediately.


When you mistakenly do this:

setTimeout(func(), 1500);
setInterval(func(), 1500);

It is executing your func() immediately and then passing the return result to setTimeout() and setInterval(). Since your func() doesn't return anything, you are essentially doing this:

func();
setTimeout(undefined, 1500);

Which is what you observe happening, but not what you want.


Further, if you want to execute a specific function call such as console.log("Bowties are cool."), then you can wrap it in another function like this:

setTimeout(function() {
    console.log("Bowties are cool.")
}, 1500);

So, again you are passing a function reference to setTimeout() that can be executed LATER rather than executing it immediately which is what you were doing.

jfriend00
  • 683,504
  • 96
  • 985
  • 979
  • What path of logic does the javascript engine take when this gets executed? What does it see first and how or in what order do the arguments get placed in the stack? Hope this question makes sense. – sufuninja Aug 21 '15 at 17:18
  • @sufuninja: If you have another question, ask another question and explain what you mean. – Matt Burland Aug 21 '15 at 17:20
  • @sufuninja - I gave you an example of the equivalent order of execution right in my answer. When you put `func()` as an argument, that is evaluated first and then the result of that is passed as the argument. – jfriend00 Aug 21 '15 at 17:32
0

setTimeout and setInterval expect a function reference to be passed to them. You should not be calling the function within the setTimeout and setInterval calls.

Incorrect (DON'T DO THIS):

setTimeout(func(), 1500);
setInterval(func(), 1500);
setTimeout(console.log("Bowties are cool."), 1500);
setInterval(console.log("Bowties are cool."), 1500);

Correct:

setTimeout(func, 1500);
setInterval(func, 1500);
setTimeout(function() {
    console.log("Bowties are cool.");
}, 1500);
setInterval(function() {
    console.log("Bowties are cool.");
}, 1500);

Note how I wrapped the console.log in an anonymous function in order to use it with setInterval and setTimeout. I could not pass console.log to the setInterval and setTimeout functions, because it needs the parameter "Bowties are cool.". Wrapping it in the anonymous function solves this.

Jake Griffin
  • 2,014
  • 12
  • 15
0

When you add parentheses after a defined function, you actually call or invoke the function.

But when you pass a function as a parameter inside another function, you don't want to call the function, you just want to pass a reference to this function as a parameter, (and the function you passed in, will be available to be called when needed).

for more about callback functions in general, here.

Shimon Brandsdorfer
  • 1,673
  • 9
  • 23