【问题标题】: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 请求都会超时(或以其他方式产生错误响应)。

标签: javascript angularjs memory-leaks promise angular-promise


【解决方案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。 (如果没有人有这个承诺,也没有人可以改变它的状态,那么它的目的是什么?)
猜你喜欢
  • 2018-07-25
  • 2021-12-03
  • 2011-02-28
  • 2021-03-23
  • 2021-09-25
  • 2014-12-08
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多