从未解决的承诺会导致内存泄漏吗?
Posted
技术标签:
【中文标题】从未解决的承诺会导致内存泄漏吗?【英文标题】:Does never resolved promise cause memory leak? 【发布时间】:2013-12-02 19:46:30 【问题描述】:我有一个Promise
。如果需要,我创建它是为了取消 AJAX 请求。但是由于我不需要取消那个 AJAX,所以我从来没有解决它并且 AJAX 成功完成。
一个简化的 sn-p:
var defer = $q.defer();
$http(url: 'example.com/some/api', timeout: defer.promise).success(function(data)
// do something
);
// Never defer.resolve() because I don't need to cancel that ajax. What happens to this promise after request?
从来没有解决过这样的承诺会导致内存泄漏吗?您对如何管理Promise
生命周期有什么建议吗?
【问题讨论】:
一个“从未解决”的承诺仍然可以被“拒绝”。您要查找的词是“未实现”。 $http 是一个有趣的例子,因为如果客户端无法访问服务器,无论传递给“超时”参数的承诺如何,最终 HTTP 请求都会超时(或以其他方式产生错误响应)。 【参考方案1】:好吧,我假设您没有明确引用它,因为这会迫使它保持分配状态。
我能想到的最简单的测试实际上是分配很多承诺而不是解决它们:
var $q = angular.injector(["ng"]).get("$q");
setInterval(function ()
for (var i = 0; i < 100; i++)
var $d = $q.defer();
$d.promise;
, 10);
然后观察堆本身。正如我们在 Chrome 分析工具中看到的那样,这会累积分配 100 个 promise 所需的内存,然后整个JSFIddle page
“停留在那里”不到 15 兆字节另一方面,如果我们看$q
source code
我们可以看到,没有从全局点到任何特定 Promise 的引用,而只是从 Promise 到它的回调。代码非常可读和清晰。让我们看看如果您确实从回调中引用了 Promise 会怎样。
var $q = angular.injector(["ng"]).get("$q");
console.log($q);
setInterval(function ()
for (var i = 0; i < 10; i++)
var $d = $q.defer();
(function ($d) // loop closure thing
$d.promise.then(function ()
console.log($d);
);
)($d);
, 10);
所以在初始分配之后 - 似乎它也能够处理它:)
如果我们让他的最后一个示例再运行几分钟,我们还可以看到一些有趣的 GC 模式。我们可以看到这需要一段时间 - 但它能够清除回调。
简而言之 - 至少在现代浏览器中 - 只要您没有对它们的外部引用,您就不必担心未解决的承诺
【讨论】:
这是否意味着如果一个 promise 需要很长时间才能解决(但会最终解决),它就有被 GC 的风险? @w.brian 除非您将其分配给某处 - 例如分配给变量:var b = $http.get(...)
或向其添加回调。这也有参考。如果某事解决了它(就像你说的 - 解决时间过长仍然意味着解决) - 它必须有一个参考。所以是的 - 它不会被 GC 处理
知道了,我就是这么想的。所以,问题是“从未解决的承诺会导致内存泄漏吗?”对于将回调传递给 Promise 的常见用例,答案是肯定的。您回答中的这一行似乎与以下内容相矛盾:“如果我们让他的最后一个示例再运行几分钟,我们还可以看到一些有趣的 GC 模式。我们可以看到这需要一段时间 - 但它能够清理回调。 "对不起,如果我是迂腐和挑剔,我只是想确保我理解这一点。
这对我来说似乎没有意义。如果我创建了 100.000 个承诺,那么 console.log() 会写上一行。如果他们突然通过某种魔法解决,我希望这 100.000 人记录这些行。或者您是说浏览器会知道这将永远解决,因为 I 和实际的浏览器都没有对它的任何引用(没有任何影响) - 那么怎么可能那是真的吗? (嗯,我知道这可能是真的)
这些 cmets 中有些道理,有些具有误导性,所以让我澄清一下:附有处理程序的承诺可能有资格进行垃圾收集。如果满足以下条件,则 Promise 将保持活动状态(不符合 GC 条件):(1) 存在对 promise 对象的引用,(2) 存在对“延迟”对象的引用承诺的状态(您用来解决/拒绝它的对象/函数)。除此之外,promise 有资格获得 GC。 (如果没有人有这个承诺,也没有人可以改变它的状态,那么它的目的是什么?)以上是关于从未解决的承诺会导致内存泄漏吗?的主要内容,如果未能解决你的问题,请参考以下文章