从未解决的Promise会导致内存泄漏吗?

IT技术 javascript angularjs memory-leaks promise angular-promise
2021-01-18 22:53:59

我有一个Promise. 我创建它是为了在需要时取消 AJAX 请求。但是由于我不需要取消那个 AJAX,所以我从来没有解决它并且 AJAX 成功完成。

一个简化的片段:

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会导致内存泄漏吗?您对如何管理Promise生命周期有什么建议吗?

1个回答

好吧,我假设您没有明确引用它,因为这会迫使它保持分配状态。

我能想到的最简单的测试实际上是分配了很多Promise而不是解决它们:

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 页面上“停留在那里”不到 15 兆字节

在此处输入图片说明

另一方面,如果我们看$q源代码

我们可以看到,没有从全局点到任何特定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

这些评论中有一些是真实的,也有一些是误导性的,所以让我澄清一下:附加了处理程序的Promise可能有资格进行垃圾收集。如果以下任一情况为真,promise 将保持活动状态(不符合 GC 资格):(1) 存在对 promise 对象的引用,(2) 存在对 promise 的“延迟”状态的引用(对象/ 用于解决/拒绝它的功能)。除此之外,promise 有资格进行 GC。(如果没有人有 Promise 并且没有人可以改变它的状态,那么它的目的是什么?)
2021-03-19 22:53:59
@w.brian 除非你将它分配到某个地方——例如给一个变量:var b = $http.get(...)或者给它添加一个回调。这也是对它的引用。如果某事解决了它(就像你说的 - 解决时间太长仍然意味着解决) - 它必须有一个对它的引用。所以是的 - 它不会被 GC'd
2021-03-24 22:53:59
知道了,我就是这么想的。所以,问题是“从未解决的Promise会导致内存泄漏吗?” 对于将回调传递给Promise的常见用例,答案是肯定的。您的回答中的这一行似乎与以下内容相矛盾:“如果我们让他的最后一个示例再运行几分钟,我们还可以看到一些有趣的 GC 模式。我们可以看到这需要一段时间 - 但它能够清除回调。 ” 对不起,如果我是迂腐和挑剔,我只是想确保我理解这一点。
2021-03-31 22:53:59
这是否意味着如果Promise需要很长时间才能解决(但最终会解决),它就有被 GC 的风险?
2021-04-01 22:53:59
这对我来说似乎没有意义。如果我创建了 100.000 条Promise,console.log() 会显示一些行。如果它们突然被某种魔法解决,我希望那些 100.000 记录这些行。或者你是说浏览器会知道这永远不会解决,因为和实际浏览器都没有对它的任何引用(没有任何影响) - 那么这怎么可能是真的?(嗯,我知道这可能是真的)
2021-04-07 22:53:59