在setTimeout中使用JavaScript闭包
我使用setTimeout来模拟渲染,然后我来到这样的结构:
var Renderer = new Class (
{
Implements: Events,
initialize()
{
this.onRender();
},
onRender: function()
{
// some rendering actions
setTimeout(this.onRender.bind(this), 20);
}
});
由于无限嵌套的闭包,该代码是否有潜在的内存泄漏? 或者一切都好? 我到目前为止唯一的解决方案是将其重写为平常
function Renderer()
{
var onRender = function()
{
// rendering
setTimeout(onRender, 20);
};
onRender();
};
但我不想失去Mootools Events和Classes。 由于某些原因,我不能使用“singleton”(如window.renderer = new Renderer();)
你的代码很好,但是Andy的回答是误导性的,因为它将作用域链与执行上下文以及扩展名调用栈混淆。
首先, setTimeout
函数不在全局范围内执行。 它们仍然在闭包中执行,并可以访问来自外部作用域的变量。 这是因为JavaScript使用静态作用域 ; 也就是说,函数的作用域链是在创建函数的时刻定义的,永远不会改变; 范围链是该功能的一个属性。
执行上下文与范围链不同并且与范围链分开,因为它是在函数被调用时构建的(不管是直接调用 - func();
还是作为浏览器调用的结果,例如超时过期)。 执行上下文由激活对象(该函数的参数和局部变量),以范围链的引用,和的值的this
。
调用堆栈可以被认为是一个执行上下文的数组。 在堆栈的底部是全局执行上下文。 每次调用函数时,其参数和this
值都将存储在堆栈中的新“对象”中。
如果我们要改变你的onRender
函数来简单调用它自己( this.onRender()
),堆栈会很快溢出。 这是因为控制永远不会离开每个连续的onRender
函数,从而允许其执行上下文从调用堆栈中弹出。 相反,我们会越来越深入,每个onRender
等待下一个onRender
返回,只有在堆栈溢出时才会崩溃。
但是,通过调用setTimeout
,控制立即返回,因此可以离开onRender
函数,使其执行上下文从堆栈弹出并丢弃(由GC从内存中释放)。
当超时到期时,浏览器从全局执行上下文启动对onRender
的调用; 调用堆栈只有两个深度。 有一个新的执行上下文-在默认情况下将继承在全球范围内为this
值; 这就是为什么你必须bind
到你的Renderer
对象 - 但它仍然包含你在第一次定义onRender
时创建的原始作用域链。
正如你所看到的,你不会通过递归创建无限闭包,因为闭包(作用域链)是在函数定义中创建的,而不是在函数调用时创建的。 此外,您不会创建无限的执行上下文,因为它们在onRender
返回后被丢弃。
我们可以确保你没有通过测试来泄漏内存。 我让它运行50万次,没有发现任何泄漏的内存。 请注意,最大调用堆栈大小约为1,000(因浏览器而异),所以绝对不会递归。
setTimeout
函数在全局范围内执行,它们不知道它们被实例化的范围上下文。 使用Javascript递归,您必须注意的是递归太深,因为每次递归调用都会创建一个新的范围上下文,并在内存中生成。 在这种情况下,setTimeout将其重置为全局范围,所以它在技术上不是递归。
编辑:这个答案是不正确的。 看评论。
链接地址: http://www.djcxy.com/p/51703.html上一篇: Using JavaScript closures in setTimeout
下一篇: PHP function returning anonymous function with use / global