我将匿名函数-A作为参数传递给另一个函数-B。即使在我调用B.destroy之后,函数A仍然存在并被执行,它甚至作为一个实时的匿名范围。我通过调试器发现了这种意外行为。以下是代码。
var builder.record.verifyExplorer = new builder.VerifyExplorer(
window.bridge.getRecordingWindow(),
builder.getScript().seleniumVersion,
function(step) {
builder.getScript().addStep(step);
builder.stepdisplay.update();
// Don't immediately stop: this would cause the listener that prevents the click from
// actually activating the selected element to be detached prematurely.
setTimeout(function() { builder.record.stopVerifyExploring(); }, 1);
window.bridge.focusRecorderWindow();
}
);
我通过将stopVerifyExploring定义为
来销毁上述功能builder.record.stopVerifyExploring = function() {
builder.record.verifyExploring = false;
builder.record.verifyExplorer.destroy();
builder.record.verifyExplorer = null;
builder.record.continueRecording();
};
即使在调用了verifyExplorer.destroy之后,函数(步骤)仍然存在于匿名作用域中并被执行并执行所有不需要的操作。
通过替换
我有这种奇怪的行为 jQuery(frame.document).bind(l, {}, ae.listeners[l], true);
与
frame.document.addEventListener(l,ae.listeners[l],true);
在verifyExplorer中。我如何更改上面的代码导致意外行为?
答案 0 :(得分:3)
行为完全没有意外,你没有取消计时器。
如果要取消定时器,请保存setTimeout
的返回值,然后在/当您想要取消定时器时将该值传递到clearTimeout
。
发生了什么:
只要任何东西都引用它们,就会存在函数和对象。当你这样做时:
setTimeout(function() { builder.record.stopVerifyExploring(); }, 1);
...您在浏览器的计时器处理中保存了对该匿名函数的引用。该函数引用了创建它的上下文(以及所有包含上下文的内容)。因此,即使您执行verifyExplorer = null
,也不会影响verifyExplorer
对象用于引用所有的任何内容,也不会影响引用该对象的任何内容。它只是从特定变量中清除对该对象的引用。如果有其他未完成的引用(并且有),则该对象将保留在内存中。
在这种情况下,如果唯一未完成的引用是您已赋予setTimeout
的功能,则清除超时(可能在destroy
中)将释放浏览器的参考该函数释放该函数对其关闭的上下文的引用,并且这些函数可以进行垃圾收集。
更多(在我的博客上):Closures are not complicated