98

我有一个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

1 回答 1

150

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

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

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

在此处输入图像描述

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

于 2013-11-19T10:23:50.797 回答