假设以下代码:
var deferred = $.Deferred();
deferred.done(function(){
// do something with events, references to dom, etc...
});
deferred.fail(function(){
// do something with events, references to dom, etc...
});
如果我从未结束调用resolve()
或fail()
,这是否会导致内存泄漏,因为我在回调中保留了引用?
如果我打电话给另一个,而不打另一个,那么另一个会被垃圾收集吗?所以如果我打电话给fail()
,jquery会摆脱done()
吗?
我可能完全错了,但想澄清一下。到目前为止,我找到的最接近的是Shall I always invoke either JQuery Deferred.resolve or Deferred.reject?。但是用例有点不同,因为在该示例中,用户从未为fail()
定义回调。
我也遇到过此问题,Can jQuery deferreds be cancelled?,但我并不想取消deferred
。
我知道这不是最佳做法,但出于问题的目的,我仍然很好奇是否会导致记忆问题。
谢谢,
答案 0 :(得分:8)
如果我从未结束调用resolve()或fail(),这会导致内存 泄漏,因为我在回调中保留了引用?
如果您的任何代码都无法访问deferred
变量本身(这也意味着根据此代码没有其他承诺),那么它将有资格进行垃圾回收,即使它从未解决过或拒绝。如果你想了解什么"可达"意味着,最好是展示您关注的实际代码。
另一方面,如果您仍然在某个地方持有deferred
变量或其他仍然可以接受的承诺取决于此承诺(这意味着这些承诺会引用此承诺) ,那么延迟对象是否已经解决并不重要,它仍然存在并且不能被垃圾收集。
Promses在垃圾收集方面只是普通的Javascript对象,所以它们遵循与普通对象相同的垃圾收集规则。
如果我打电话给另一个,而不是另一个,那么另一个会被垃圾收集吗? 因此,如果我调用fail(),jquery将摆脱done()。
代码本身并没有收集垃圾。它是收集垃圾的变量和对象的内容。因此,在您显示的代码中,它是作为垃圾收集主题的deferred
变量(变量指向的promise对象)的内容。而且,正如我上面所说的那样,无论你是否已经解决,拒绝或两者都没有。重要的是,如果您的代码仍然可以访问该对象。如果任何代码仍然可以访问deferred
变量,或者任何其他代码或承诺仍然可以访问此承诺。
例如,如果我在页面中有这个顶级代码:
<script>
var deferred = $.Deferred();
deferred.done(function(){
// do something with events, references to dom, etc...
});
deferred.resolve();
</script>
deferred
变量仍然可以访问且仍然存活,因此它指向的Deferred对象不能被垃圾回收。
或者,如果我有这个:
<script>
$("#submit").click(function() {
var p = $.get(myURL);
p.done(function(data) {
if (data) {
$("#msg").html(data.msg);
}
});
});
</script>
然后,只要ajax调用完成并调用.done()
处理程序,就不再有任何代码可以访问p
变量的实例,因为ajax操作已完成它将释放对promise的引用,因此它不能触发任何更多的promise回调本身。并且,它已经超出了单击处理程序回调函数的范围,并且没有可以访问p
的实时事件处理程序,因此它已无法访问。此时,它将有资格进行垃圾收集。