2

I'm trying to understand how the callback function works inside the setTimeout function. I'm aware the format is: setTimeout(callback, delay) I wrote a little test script to explore this.

test1.js

console.log("Hello")

setTimeout(function () { console.log("Goodbye!") }, 5000)

console.log("Non-blocking")

This works as expected, printing Hello <CRLF> Non-blocking and then 5 seconds later, prints Goodbye!

I then wanted to bring the function outside of the setTimeout like this:

console.log("Hello")

setTimeout(goodbye(), 5000)

console.log("Non-blocking")

function goodbye () {
    console.log("Goodbye")
}

but it doesn't work and there isn't a 5 second delay between Non-blocking and Goodbye!, they print straight after each other.

It works if I remove the brackets from the function call in the timeout, like this:

setTimeout(goodbye, 5000)

but this doesn't make sense to me because that's not how you call a function. Futhermore, how would you pass arguments to the function if it looked like this?!

var name = "Adam"    

console.log("Hello")

setTimeout(goodbye(name), 5000)

console.log("Non-blocking")

function goodbye (name) {
    console.log("Goodbye "+name)
}

My question is really, why doesn't it work when there are parameters in the function, despite the fact the setTimeout is being provided with a valid function with the correct syntax?

admrply
  • 159
  • 3
  • 16
  • 2
    It makes perfect sense, you don't want to ***call*** the function, you want to reference it so it can be called later by `setTimeout`, hence no parentheses. This doesn't just go for Node, it's basic javascript. – adeneo Apr 05 '15 at 17:10
  • [How can I pass a parameter to a setTimeout() callback?](http://stackoverflow.com/questions/1190642), [Calling functions with setTimeout()](http://stackoverflow.com/questions/3800512) – t.niese Apr 05 '15 at 17:13
  • 1
    If you replace the variable with the function definition, you will notice the difference: Replacing `goodbye` in `setTimeout(goodbye(), 5000)` becomes `setTimeout(function goodbye() { ... ) }(), 5000)`. Do you notice the trailing `()`? They don't appear in `setTimeout(function () { ... }, 5000)` – Felix Kling Apr 05 '15 at 17:14
  • And if you think about it, it behaves exactly as expected. `setTimeout` is not magical, it basically behaves like any other function: Arguments are evaluated before they are passed to the callee. If you have `foo(bar())`, then `bar` is executed first and its return value is passed to `foo`. That's how *every* function call works in JavaScript. – Felix Kling Apr 05 '15 at 17:17

3 Answers3

6

By putting the parentheses after your function name, you are effectively calling it, and not passing the function as a callback.

To provide parameters to the function you are calling:

  1. You can pass an anon function. setTimeout(function(){goodbye(name)}, 5000);
  2. Or, you can pass the arguments as a third parameter. setTimeout(goodbye, 5000, name);

Look at this question: How can I pass a parameter to a setTimeout() callback?

Community
  • 1
  • 1
tmj
  • 1,750
  • 2
  • 19
  • 34
  • Ah that makes sense! I'm guessing the reason it doesn't call the anon function straight away is because it's being declared and not called? Is that right? – admrply Apr 05 '15 at 17:21
  • 1
    Yes. It would have been called if the code was somthing like this. `setTimeout(function(){ goodbye(name); }(), 5000);` Notice the parentheses at the end of the anon function. – tmj Apr 05 '15 at 17:23
3

No matter where you place it, goodbye(name) executes the function immediately. So you should instead pass the function itself to setTimeout(): setTimeout(goodbye, 5000, name).

mscdex
  • 104,356
  • 15
  • 192
  • 153
3

When you use it like this:

setTimeout(goodbye(), 5000);

it will first call goodbye to get its return value, then it will call setTimeout using the returned value.

You should call setTimeout with a reference to a callback function, i.e. only specifying the name of the function so that you get its reference instead of calling it:

setTimeout(goodbye, 5000);

To make a function reference when you want to send a parameter to the callback function, you can wrap it in a function expression:

setTimeout(function() { goodbye(name); }, 5000);

You can use parantheses in the call, but then the function should return a function reference to the actual callback function:

setTimeout(createCallback(), 5000);

function createCallback() {
  return function() {
    console.log("Goodbye");
  };
}
Guffa
  • 687,336
  • 108
  • 737
  • 1,005