moj*_*uba 36 javascript closures
假设我有类似的东西
function animate(param)
{
// ...
if (param < 10)
setTimeout(function () { animate(param + 1) }, 100);
}
animate(0);
Run Code Online (Sandbox Code Playgroud)
这是否意味着函数的本地数据的每个实例都将保存在内存中,直到有效完成,即直到param达到10?
如果实例保存在内存中,有没有更好的方法呢?我知道,传递文本代码来setTimeout()解决问题,但在我的情况下,函数参数中的对象不能轻易地表示为字符串.
Wla*_*ant 13
不,最多两个函数的本地数据实例将在任何给定的时间点保存在内存中.以下是事件的顺序:
animate(0) 叫做.param == 0创建了一个闭包,它现在可以防止释放此变量.animate(1)被称为.param == 1创建了新的闭包,它现在可以防止释放此变量.animate()调用的局部变量现在也可以释放.animate(2).实际上,你没有在那里创建递归函数.通过调用setTimeout它不再调用自己.这里创建的唯一闭包是匿名函数setTimeout,一旦执行,垃圾收集器就会识别出对前一个实例的引用可以被清除.这可能不会立即发生,但你stack overflow肯定无法创建使用它.让我们看看这个例子:
function myFunc() {
var bigarray = new Array(10000).join('foobar');
setTimeout(myFunc, 200);
}
myFunc();
Run Code Online (Sandbox Code Playgroud)
现在就从浏览器中查看内存使用情况.它会不断增长,但过了一段时间(对我来说是20-40秒)它会再次彻底清洁.另一方面,如果我们创建一个真正的递归,如下所示:
function myFunc() {
var bigarray = new Array(10000).join('foobar');
myFunc();
}
myFunc();
Run Code Online (Sandbox Code Playgroud)
我们的内存使用量将增长,浏览器会锁定,我们最终会创建它stack overflow.Javascript 没有实现Tail递归,因此我们最终会在所有情况下都出现溢出.
更新
在我的第一个例子中看起来我错了.只有在没有调用函数上下文的情况下(例如,使用匿名函数),该行为才有效.如果我们重写那样的话
function myFunc() {
var bigarray = new Array(10000).join('foobar');
setTimeout(function() {
myFunc();
}, 200);
}
myFunc();
Run Code Online (Sandbox Code Playgroud)
浏览器内存似乎不再被释放.永远长大.这可能是因为任何内部关闭都会引用bigarray.但无论如何.