永远不会解决的承诺会导致内存泄漏吗?


91

我有一个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生命周期有任何建议吗?


4
“从未解决”的承诺仍然可以被“拒绝”。您要查找的单词是“未完成”。
史蒂文·瓦雄

$ http是一个有趣的示例,因为如果客户端无法访问服务器,无论传递给'timeout'参数的承诺如何,最终HTTP请求都会超时(否则将产生错误响应)。
ryanwebjackson

Answers:


144

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

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

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模式。我们可以看到它需要一段时间-但它能够清除回调。

在此处输入图片说明

简而言之-至少在现代浏览器中-您不必担心未解决的承诺,只要您没有对它们的外部引用


7
这是否意味着如果一个承诺花费太长时间来解决(但最终会解决),那么就有被GC兑现的风险了吗?
w.brian 2014年

5
@ w.brian,除非您将其分配到某个位置(例如,分配给变量):var b = $http.get(...)或向其添加回调。那也有参考。如果某件事可以解决它(如您所说-解决太久仍然意味着解决)-它必须具有对它的引用。所以是的-它不会被GC
Benjamin Gruenbaum

3
知道了,这就是我的想法。因此,问题是“永不解决的诺言会导致内存泄漏吗?” 对于将回调传递给Promise的常见用例,答案是肯定的。您的答案中的这一行似乎与以下事实矛盾:“如果让他的上一个示例再运行几分钟,我们还可以看到一些有趣的GC模式。我们可以看到它花了一段时间-但它能够清理回调。 ” 抱歉,如果我要学步又挑剔,我只是想确保自己理解这一点。
w.brian 2014年

1
这对我来说似乎没有意义。如果我创建了100.000,则保证console.log()有一行。如果它们突然被某种魔术解决,我希望那些100.000记录这些行。还是您是说浏览器将知道这将永远无法解决,因为和实际的浏览器都没有对此的引用(没有任何影响)-那么这怎么可能呢?(嗯,我看得出这可能是真的)
odinho-Velmont,2016年

8
这些评论中有些真相,有些是误导性的,所以让我澄清一下:附加了处理程序的诺言可能有资格进行垃圾回收。如果满足以下一条件,则诺言将保持有效(不符合GC资格):(1)对诺言对象的引用,(2)对诺言的“延迟”状态(对象)的引用/您用来解决/拒绝它的功能)。除此以外,promise也有资格获得GC。(如果没有人有诺言并且没有人可以改变其状态,那么它的目的又是什么?)
cdhowie
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.