Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Understanding javascript closures and memory usage

EDIT: This is just a simple example to demontrate the concern I have with a much larger program. I wouldn't use this actual code for anything :)

If I run this -

<!DOCTYPE html>
<html>
<head>
<script>

function update(amount, win, data)
{
    win.innerText = 'Count is ' + amount;
    setTimeout(function() { update(amount + 1, win, {data: 'something'})}, 1000);
}

window.onload = function() {

  var win = document.getElementById('item');    
  update(0, win, 0);
}
</script>
</head>

<body>
<div id="item"></div>
</body>
</html>

The call to setTimeout presumably creates a closure which captures the contents of the parameters to the "update" function (amount, win, data). So those variables are maintained in memory until the timeout is called and returns so that they will be available inside that function call...

But that function creates a new closure for the next iteration of the timeout... What will be captured in that second closure? Is it just the new copies of those variables or will the ones that formed part of the function call be captured again in the new closure?

Basically will this eventually run out of memory due to the data in each closure getting bigger and bigger, or is this safe and reasonable?

like image 229
jcoder Avatar asked Jun 01 '11 16:06

jcoder


1 Answers

In my understanding, when a closure is created, the current lexical context is bundled with it. In your case, it would be the amount, win, data.

This context will be used, when the timeout fires, to execute the closure and thus call once again the function update; this call, although it might appear so, is not recursive, because the previous execution of update already ended and its original context (dynamic, which is different from the lexical one) has already been freed. (I think this is important to notice, because it seems you are worrying about a sort of stack growth due to recursion).

So, again, update is executed a second time and again a timeout is set and a closure created. This closure is bundled with the current lexical context of execution (which still includes just amount, win, data) and scheduled with the timer. then update finishes and removed from the stack. then again the timer fires and update is called again...

So, you should not worry about an unlimited growth of the context, for two reasons: first, only the lexical context is bundled with the closure; the call is not actually recursive.

like image 134
sergio Avatar answered Sep 20 '22 21:09

sergio