1. ホーム
  2. javascript

[解決済み] 解決されない約束はメモリリークの原因になりますか?

2023-01-10 18:11:15

質問

私は 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 のライフサイクルを管理する方法についてのアドバイスはありますか?

どのように解決するのですか?

まあ、強制的に割り当てられたままになってしまうので、明示的な参照を保持していないのでしょうけど。

私が考えついた最も単純なテストは、実際に多くの約束を割り当てて、それらを解決しないことです。

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 個の約束を割り当てるために必要なメモリを蓄積し、その後、全体のために 15 メガバイト未満でちょうどそこにとどまります。 JSFIddle ページ

反対側から見てみると $q ソースコード

グローバルポイントから特定のプロミスへの参照はなく、プロミスからそのコールバックへの参照のみであることがわかります。このコードは非常に読みやすく、明確です。しかし、コールバックからプロミスへの参照がある場合はどうなるのか見てみましょう。

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 のいくつかの興味深いパターンを見ることもできます。しばらく時間がかかりますが、コールバックをクリーンアップできていることがわかります。

要するに、少なくともモダンブラウザでは、外部参照を持たない限り、未解決のプロミスについて心配する必要はないのです。