2

Okay, so in the following bit of code basically I want my function to take an input in milliseconds, and then print out the message with the iteration it's on, and the amount of milliseconds it took. And it just needs to loop.

let count = 0

function timerFunction(miliseconds) {
  setTimeout(function() {
    console.log('This is iteration number: ' + ++count + ' and it took this many miliseconds to do the iteration:' + miliseconds)
    timerFunction(miliseconds)
  }, miliseconds)
}

timerFunction(2000)

That works as intended. All good.

However, if I make that function specified in setTimeout a IIFE function like so:

let count = 0

function timerFunction(miliseconds) {
  setTimeout((function() {
    console.log('This is iteration number: ' + ++count + ' and it took this many miliseconds to do the iteration:' + miliseconds)
    timerFunction(miliseconds)
  })(), miliseconds)
}

timerFunction(2000)

It seems to ignore the timeout, loop really fast, and then node.js gives a stack overflow error.

How come making that function in setTimeout a IIFE function, makes such a difference? I can't get my head around it.

Cheers guys.

Pointy
  • 405,095
  • 59
  • 585
  • 614
Jim Jay
  • 55
  • 3
  • 1
    Well you're **calling** the function (by adding `()` after it), and that function call will happen **before** the call to `setTimeout()`. – Pointy Sep 23 '21 at 14:50
  • 1
    ... And thus the inner call to `timerFunction()` *also* happens before the call to `setTimeout()`, resulting in the stack overflow. – Pointy Sep 23 '21 at 14:54
  • 1
    The "II" in IIFE stands for **immediately invoked**. – Pointy Sep 23 '21 at 14:55
  • Fantastic, thank you. Could not get my head around that, but it's actually quite simple. So basically the setTimeout function is using the milisecond attrib to decide when to call my function. But that gets ignored when I tell the function to execute immediately. – Jim Jay Sep 23 '21 at 14:58
  • Yes. JavaScript, like most popular and similar languages, is "applicative", which means (among lots of other stuff) that function argument expressions are evaluated *before* the function is called. (My terminology may be a little off, but that's how it works nevertheless.) So that invocation happens, and when you get the stack overflow, `setTimeout()` ultimately is never called at all. – Pointy Sep 23 '21 at 15:04
  • Thank you for the explanation. I'm new to stack overflow and looks like I can't mark your comments as the correct answer? But thank you anyway! – Jim Jay Sep 23 '21 at 15:05

1 Answers1

1

In the first example the timerFunction will be called after a minimum of 2000 ms (actually, when the event loop will take that callback function timerFunction from the callback queue after the platform (which can be the browser or node.js) will finish taking care of the count down), so the timerFunction will be called again with it's new stack (recursive).

In your second example, the setTimeout method is invoked immediately (IIFE stand for immediately invoked function expression) because applying the () at the end, hence, the timerFunction is being called again (and again again...), so the 'miliseconds' argument has no actual meaning.

Here is a good article from medium explaining it: https://medium.com/@devinmpierce/recursive-settimeout-8eb953b02b98

Ran Turner
  • 14,906
  • 5
  • 47
  • 53