简体   繁体   English

了解javascript闭包和内存使用情况

[英]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). 对setTimeout的调用可能会创建一个闭包,它将参数的内容捕获到“更新”函数(金额,胜利,数据)。 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? 基本上,由于每个闭包中的数据变得越来越大,这最终会耗尽内存,还是这样安全合理?

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 . 在你的情况下,它将是amount, win, data

This context will be used, when the timeout fires, to execute the closure and thus call once again the function update ; 当超时触发时,将使用该上下文来执行闭包,从而再次调用函数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. 虽然看起来如此,但这个调用并不是递归的,因为先前的update执行已经结束,并且其原始上下文(动态,与词法不同)已经被释放。 (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. 因此,再次执行update第二次并再次设置超时并创建闭包。 This closure is bundled with the current lexical context of execution (which still includes just amount, win, data ) and scheduled with the timer. 此闭包与当前词汇执行的上下文(其中仍包括amount, win, data )捆绑在一起,并与计时器一起安排。 then update finishes and removed from the stack. 然后update完成并从堆栈中删除。 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. 该调用实际上不是递归的。

A new closure is created every time the timeout callback is called, as you correctly say. 正如您所说的,每次调用超时回调时都会创建一个新的闭包。 But once the callback has been executed, there is no longer anything referencing the previous closure, so it can be garbage collected. 但是一旦执行了回调,就不再有任何引用前一个闭包的东西了,所以它可以被垃圾收集。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM