使用 this/self 引用的 JavaScript 闭包是否会导致内存泄漏?

发布于 2025-01-06 09:31:12 字数 389 浏览 0 评论 0原文

根据我对内存泄漏的理解,在闭包中引用超出范围的 var 将导致内存泄漏。

但创建“that”变量以保留“this”引用并在闭包中使用它也是一种常见的做法,尤其是对于事件。

那么,做这样的事情是怎么回事:

SomeObject.prototype.createImage = function(){
    var that = this,
        someImage = new Image();
    someImage.src = 'someImage.png';
    someImage.onload = function(){
        that.callbackImage(this);
    }
};

这不会给项目增加一点泄漏吗?

From what I understand about memory leaks, referencing an out-of-scope var within a closure will cause a memory leak.

But it is also a common practice to create a "that" var in order to preserve the "this" reference and use it within a closure, especially for events.

So, what's the deal with doing stuff like this:

SomeObject.prototype.createImage = function(){
    var that = this,
        someImage = new Image();
    someImage.src = 'someImage.png';
    someImage.onload = function(){
        that.callbackImage(this);
    }
};

Wouldn't that add a little leakage to a project?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

饮湿 2025-01-13 09:31:13

是的,是的,它确实会导致内存泄漏,至少在某些浏览器中(猜猜是哪个)。这是信任各种可用框架之一并通过其机制设置所有事件处理程序而不是像这样直接添加“DOM 0”事件处理程序的更令人信服的原因之一。

Internet Explorer(至少在 9 之前,并且可能包括 9)在内部(至少)有两种内存分配机制:一种用于 DOM,一种用于 JavaScript(以及 JScript)。他们互相不理解。因此,即使释放 DOM 节点,您示例中的任何闭包内存也不会被释放。

编辑 - 哦,我提到框架的原因是它们通常包含尝试缓解这个问题的代码。避免将任何内容附加到 DOM 节点属性是最安全的方法之一。例如,所有值得担心的浏览器(包括古老的 IE 版本)都有将事件处理程序附加到 DOM 节点的替代方法。

Yes, yes it does cause memory leaks, at least in some browsers (guess which). This is one of the more compelling reasons to put your trust in one of the various frameworks available and to set up all your event handlers via its mechanisms instead of directly adding "DOM 0" event handlers like that.

Internet Explorer (at least prior to 9, and possibly including 9) has two memory allocation mechanisms (at least) internally: one for the DOM, and one for JavaScript (well JScript). They don't understand each other. Thus even if a DOM node is freed up, any closure memory as in your example will not be freed.

edit — Oh, and the reason I mention frameworks is that they generally include code to try and mitigate this problem. The avoidance of attaching anything to DOM node properties is one of the safest approaches. All browsers worth worrying about (including ancient IE versions) have alternative ways of attaching event handlers to DOM nodes, for example.

一桥轻雨一伞开 2025-01-13 09:31:13

这里是在黑暗中拍摄的,但我认为:

someImage.onload = function(){
    that.callbackImage(this);
    someImage.onload = null
}

会清理 that 留下的“内存泄漏”

Shot in the dark here, but I reckon that:

someImage.onload = function(){
    that.callbackImage(this);
    someImage.onload = null
}

would clean up the "memory leak" left by that

叫嚣ゝ 2025-01-13 09:31:13

曾经有一段时间,IE 涉及 DOM 元素的循环引用(通常是在将函数分配给侦听器时由闭包形成)导致内存泄漏,例如,

function foo() {
  var someEl = document.getElementById('...');
  someEl.onclick = function() {...};
}

但是,我认为它们已得到充分修复或修补,除非测试另有说明,否则它们可以被忽略。还有许多方法可以避免此类闭包,因此即使它们是一个问题,也可以解决它们(例如,不要创建涉及 DOM 元素的循环引用)。

编辑

使用库或任何其他附加侦听器的方法仍然可以创建循环引用和内存泄漏,例如在 IE 中:

function foo() {
  var el = document.getElementById('d0');

  // Create circular reference through closure to el
  el.attachEvent('onclick', function(){bar(el);});

}

function bar(o) {
  alert(o == window.event.srcElement);  // true
}

window.onload = foo;

上面使用 attachEvent 添加侦听器(几乎全部框架将用于 IE < 9,包括 jQuery),但仍然会创建涉及 DOM 元素的循环引用,因此在某些版本的 IE 中会发生泄漏。因此,仅使用库并不能解决问题,您需要了解原因并避免它们。

There was a time with IE that circular references involving DOM elements (which were typically formed by closures when assigning a function to a listener) caused memory leaks, e.g.

function foo() {
  var someEl = document.getElementById('...');
  someEl.onclick = function() {...};
}

However, I think they are fixed or patched sufficiently that unless testing shows otherwise, they can be ignored. There are also a number of ways to avoid such closures, so even if they are an issue, they can be worked around (e.g. don't create circular references involving DOM elements).

Edit

Using libraries or any other method of attaching listeners can still create circular references and memory leaks, e.g. in IE:

function foo() {
  var el = document.getElementById('d0');

  // Create circular reference through closure to el
  el.attachEvent('onclick', function(){bar(el);});

}

function bar(o) {
  alert(o == window.event.srcElement);  // true
}

window.onload = foo;

The above uses attachEvent to add a listener (which pretty much all frameworks will use for IE < 9, including jQuery) yet still creates a circular reference involving a DOM element and so will leak in certain versions of IE. So just using a library will not fix the issue, you need to understand the causes and avoid them.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文